Updated to Symfony 2.1 BETA3
This commit is contained in:
parent
7a06301624
commit
9d0d2ce524
|
@ -429,11 +429,11 @@ class SymfonyRequirements extends RequirementCollection
|
|||
);
|
||||
|
||||
if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) {
|
||||
$this->addRequirement(
|
||||
(in_array(date_default_timezone_get(), DateTimeZone::listIdentifiers())),
|
||||
sprintf('Default timezone is deprecated (%s)', date_default_timezone_get()),
|
||||
'Fix your <strong>php.ini</strong> file (list of deprecated timezones http://us.php.net/manual/en/timezones.others.php).'
|
||||
);
|
||||
$this->addRequirement(
|
||||
(in_array(date_default_timezone_get(), DateTimeZone::listIdentifiers())),
|
||||
sprintf('Default timezone "%s" is not supported by your installation of PHP', date_default_timezone_get()),
|
||||
'Fix your <strong>php.ini</strong> file (check for typos and have a look at the list of deprecated timezones http://php.net/manual/en/timezones.others.php).'
|
||||
);
|
||||
}
|
||||
|
||||
$this->addRequirement(
|
||||
|
@ -492,6 +492,12 @@ class SymfonyRequirements extends RequirementCollection
|
|||
|
||||
/* optional recommendations follow */
|
||||
|
||||
$this->addRecommendation(
|
||||
version_compare($installedPhpVersion, '5.3.4', '>='),
|
||||
sprintf('Your project might not work properly ("Notice: Trying to get property of non-object") due to the PHP bug #52083 before PHP 5.3.4 (%s installed)', $installedPhpVersion),
|
||||
'Install PHP 5.3.4 or newer'
|
||||
);
|
||||
|
||||
$this->addRecommendation(
|
||||
version_compare($installedPhpVersion, '5.3.8', '>='),
|
||||
sprintf('Annotations might not work properly due to the PHP bug #55156 before PHP 5.3.8 (%s installed)', $installedPhpVersion),
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Symfony\Component\DependencyInjection
|
|||
interface ContainerAwareInterface
|
||||
{
|
||||
|
||||
function setContainer(ContainerInterface $container = null);
|
||||
public function setContainer(ContainerInterface $container = null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,37 +35,37 @@ interface ContainerInterface
|
|||
const SCOPE_PROTOTYPE = 'prototype';
|
||||
|
||||
|
||||
function set($id, $service, $scope = self::SCOPE_CONTAINER);
|
||||
public function set($id, $service, $scope = self::SCOPE_CONTAINER);
|
||||
|
||||
|
||||
function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);
|
||||
|
||||
|
||||
function has($id);
|
||||
public function has($id);
|
||||
|
||||
|
||||
function getParameter($name);
|
||||
public function getParameter($name);
|
||||
|
||||
|
||||
function hasParameter($name);
|
||||
public function hasParameter($name);
|
||||
|
||||
|
||||
function setParameter($name, $value);
|
||||
public function setParameter($name, $value);
|
||||
|
||||
|
||||
function enterScope($name);
|
||||
public function enterScope($name);
|
||||
|
||||
|
||||
function leaveScope($name);
|
||||
public function leaveScope($name);
|
||||
|
||||
|
||||
function addScope(ScopeInterface $scope);
|
||||
public function addScope(ScopeInterface $scope);
|
||||
|
||||
|
||||
function hasScope($name);
|
||||
public function hasScope($name);
|
||||
|
||||
|
||||
function isScopeActive($name);
|
||||
public function isScopeActive($name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ namespace Symfony\Component\DependencyInjection
|
|||
interface IntrospectableContainerInterface extends ContainerInterface
|
||||
{
|
||||
|
||||
function initialized($id);
|
||||
public function initialized($id);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -340,13 +340,13 @@ class Container implements IntrospectableContainerInterface
|
|||
}
|
||||
|
||||
|
||||
static public function camelize($id)
|
||||
public static function camelize($id)
|
||||
{
|
||||
return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $id);
|
||||
}
|
||||
|
||||
|
||||
static public function underscore($id)
|
||||
public static function underscore($id)
|
||||
{
|
||||
return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($id, '_', '.')));
|
||||
}
|
||||
|
@ -356,23 +356,6 @@ class Container implements IntrospectableContainerInterface
|
|||
|
||||
|
||||
|
||||
namespace Symfony\Component\HttpKernel
|
||||
{
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
||||
interface TerminableInterface
|
||||
{
|
||||
|
||||
function terminate(Request $request, Response $response);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Symfony\Component\HttpKernel
|
||||
{
|
||||
|
||||
|
@ -386,7 +369,7 @@ interface HttpKernelInterface
|
|||
const SUB_REQUEST = 2;
|
||||
|
||||
|
||||
function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);
|
||||
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,55 +388,72 @@ use Symfony\Component\Config\Loader\LoaderInterface;
|
|||
interface KernelInterface extends HttpKernelInterface, \Serializable
|
||||
{
|
||||
|
||||
function registerBundles();
|
||||
public function registerBundles();
|
||||
|
||||
|
||||
function registerContainerConfiguration(LoaderInterface $loader);
|
||||
public function registerContainerConfiguration(LoaderInterface $loader);
|
||||
|
||||
|
||||
function boot();
|
||||
public function boot();
|
||||
|
||||
|
||||
function shutdown();
|
||||
public function shutdown();
|
||||
|
||||
|
||||
function getBundles();
|
||||
public function getBundles();
|
||||
|
||||
|
||||
function isClassInActiveBundle($class);
|
||||
public function isClassInActiveBundle($class);
|
||||
|
||||
|
||||
function getBundle($name, $first = true);
|
||||
public function getBundle($name, $first = true);
|
||||
|
||||
|
||||
function locateResource($name, $dir = null, $first = true);
|
||||
public function locateResource($name, $dir = null, $first = true);
|
||||
|
||||
|
||||
function getName();
|
||||
public function getName();
|
||||
|
||||
|
||||
function getEnvironment();
|
||||
public function getEnvironment();
|
||||
|
||||
|
||||
function isDebug();
|
||||
public function isDebug();
|
||||
|
||||
|
||||
function getRootDir();
|
||||
public function getRootDir();
|
||||
|
||||
|
||||
function getContainer();
|
||||
public function getContainer();
|
||||
|
||||
|
||||
function getStartTime();
|
||||
public function getStartTime();
|
||||
|
||||
|
||||
function getCacheDir();
|
||||
public function getCacheDir();
|
||||
|
||||
|
||||
function getLogDir();
|
||||
public function getLogDir();
|
||||
|
||||
|
||||
function getCharset();
|
||||
public function getCharset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Symfony\Component\HttpKernel
|
||||
{
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
|
||||
interface TerminableInterface
|
||||
{
|
||||
|
||||
public function terminate(Request $request, Response $response);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,12 +502,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface
|
|||
protected $classes;
|
||||
protected $errorReportingLevel;
|
||||
|
||||
const VERSION = '2.1.0-BETA2';
|
||||
const VERSION = '2.1.0-DEV';
|
||||
const VERSION_ID = '20100';
|
||||
const MAJOR_VERSION = '2';
|
||||
const MINOR_VERSION = '1';
|
||||
const RELEASE_VERSION = '0';
|
||||
const EXTRA_VERSION = 'BETA';
|
||||
const EXTRA_VERSION = 'DEV';
|
||||
|
||||
|
||||
public function __construct($environment, $debug)
|
||||
|
@ -516,7 +516,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface
|
|||
$this->debug = (Boolean) $debug;
|
||||
$this->booted = false;
|
||||
$this->rootDir = $this->getRootDir();
|
||||
$this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir));
|
||||
$this->name = $this->getName();
|
||||
$this->classes = array();
|
||||
|
||||
if ($this->debug) {
|
||||
|
@ -706,6 +706,10 @@ abstract class Kernel implements KernelInterface, TerminableInterface
|
|||
|
||||
public function getName()
|
||||
{
|
||||
if (null === $this->name) {
|
||||
$this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir));
|
||||
}
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
@ -975,7 +979,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface
|
|||
}
|
||||
|
||||
|
||||
static public function stripComments($source)
|
||||
public static function stripComments($source)
|
||||
{
|
||||
if (!function_exists('token_get_all')) {
|
||||
return $source;
|
||||
|
@ -1084,28 +1088,28 @@ use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
|||
interface BundleInterface extends ContainerAwareInterface
|
||||
{
|
||||
|
||||
function boot();
|
||||
public function boot();
|
||||
|
||||
|
||||
function shutdown();
|
||||
public function shutdown();
|
||||
|
||||
|
||||
function build(ContainerBuilder $container);
|
||||
public function build(ContainerBuilder $container);
|
||||
|
||||
|
||||
function getContainerExtension();
|
||||
public function getContainerExtension();
|
||||
|
||||
|
||||
function getParent();
|
||||
public function getParent();
|
||||
|
||||
|
||||
function getName();
|
||||
public function getName();
|
||||
|
||||
|
||||
function getNamespace();
|
||||
public function getNamespace();
|
||||
|
||||
|
||||
function getPath();
|
||||
public function getPath();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1348,6 +1352,7 @@ namespace Symfony\Component\HttpKernel
|
|||
|
||||
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
|
||||
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
|
||||
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
|
||||
|
@ -1450,14 +1455,27 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface
|
|||
$event = new GetResponseForExceptionEvent($this, $request, $type, $e);
|
||||
$this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event);
|
||||
|
||||
$e = $event->getException();
|
||||
|
||||
if (!$event->hasResponse()) {
|
||||
throw $e;
|
||||
}
|
||||
|
||||
$response = $event->getResponse();
|
||||
|
||||
if (!$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) {
|
||||
if ($e instanceof HttpExceptionInterface) {
|
||||
$response->setStatusCode($e->getStatusCode());
|
||||
$response->headers->add($e->getHeaders());
|
||||
} else {
|
||||
$response->setStatusCode(500);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->filterResponse($event->getResponse(), $request, $type);
|
||||
return $this->filterResponse($response, $request, $type);
|
||||
} catch (\Exception $e) {
|
||||
return $event->getResponse();
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@
|
|||
"sensio/framework-extra-bundle": "dev-master",
|
||||
"sensio/generator-bundle": "dev-master",
|
||||
"jms/security-extra-bundle": "1.1.*",
|
||||
"jms/di-extra-bundle": "1.0.*"
|
||||
"jms/di-extra-bundle": "1.0.*",
|
||||
"egeloen/ckeditor-bundle": "2.0.*"
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": [
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"hash": "ab7ccf177098603cace942212179431f",
|
||||
"hash": "0890891a613a13d9980307e458190353",
|
||||
"packages": [
|
||||
{
|
||||
"package": "doctrine/common",
|
||||
|
@ -8,20 +8,23 @@
|
|||
{
|
||||
"package": "doctrine/dbal",
|
||||
"version": "2.2.x-dev",
|
||||
"source-reference": "b961a3fce6bf220f1dca47d7d747b9074bea4730",
|
||||
"commit-date": "1341779435"
|
||||
"source-reference": "b961a3fce6bf220f1dca47d7d747b9074bea4730"
|
||||
},
|
||||
{
|
||||
"package": "doctrine/doctrine-bundle",
|
||||
"version": "dev-master",
|
||||
"source-reference": "c9ea46d1f0c48bb88bb87b44214fe44e03c0c692",
|
||||
"commit-date": "1341405737"
|
||||
"source-reference": "c9ea46d1f0c48bb88bb87b44214fe44e03c0c692"
|
||||
},
|
||||
{
|
||||
"package": "doctrine/orm",
|
||||
"version": "2.2.x-dev",
|
||||
"source-reference": "5d2a3bcb3b467f41ee58575764f3ba84937f76e4",
|
||||
"commit-date": "1341676080"
|
||||
"source-reference": "5d2a3bcb3b467f41ee58575764f3ba84937f76e4"
|
||||
},
|
||||
{
|
||||
"package": "egeloen/ckeditor-bundle",
|
||||
"version": "2.0.x-dev",
|
||||
"source-reference": "ca9d4a631577d7195c6517dd89ae8a3cc02b85ba",
|
||||
"commit-date": "1337272707"
|
||||
},
|
||||
{
|
||||
"package": "jms/aop-bundle",
|
||||
|
@ -52,8 +55,7 @@
|
|||
{
|
||||
"package": "kriswallsmith/assetic",
|
||||
"version": "dev-master",
|
||||
"source-reference": "d6f89a3170c5280ad554347dc113eb25fdf00ad7",
|
||||
"commit-date": "1339515714"
|
||||
"source-reference": "d6f89a3170c5280ad554347dc113eb25fdf00ad7"
|
||||
},
|
||||
{
|
||||
"package": "monolog/monolog",
|
||||
|
@ -62,20 +64,20 @@
|
|||
{
|
||||
"package": "sensio/distribution-bundle",
|
||||
"version": "dev-master",
|
||||
"source-reference": "9a7dbd867fd5061e4bfd660a175aa66122f53d25",
|
||||
"commit-date": "1341741741"
|
||||
"source-reference": "5886adae1613c0a72fbb95259a83ae798e86c0d3",
|
||||
"commit-date": "1342347850"
|
||||
},
|
||||
{
|
||||
"package": "sensio/framework-extra-bundle",
|
||||
"version": "dev-master",
|
||||
"source-reference": "4f54e5d5fb3b54fb107892684018f3704934c48d",
|
||||
"commit-date": "1341126219"
|
||||
"source-reference": "e9ac8f1a911ed29e30296c7f1549f53d4c94eddf",
|
||||
"commit-date": "1342084432"
|
||||
},
|
||||
{
|
||||
"package": "sensio/generator-bundle",
|
||||
"version": "dev-master",
|
||||
"source-reference": "43ed45c48db18e4a0e48aec0c098f42e56e22d36",
|
||||
"commit-date": "1340138445"
|
||||
"source-reference": "c17dbddefe517e3adfcbeaa1ab7cef3e572d29c6",
|
||||
"commit-date": "1342195488"
|
||||
},
|
||||
{
|
||||
"package": "swiftmailer/swiftmailer",
|
||||
|
@ -86,25 +88,25 @@
|
|||
{
|
||||
"package": "swiftmailer/swiftmailer",
|
||||
"version": "dev-master",
|
||||
"source-reference": "f51b5f33c83b48faea75f1285f99a2e8f1c66f75",
|
||||
"commit-date": "1341746460"
|
||||
"source-reference": "8b2aa953f87da228ba413e8fb1372e49c1374050",
|
||||
"commit-date": "1342198037"
|
||||
},
|
||||
{
|
||||
"package": "symfony/assetic-bundle",
|
||||
"version": "dev-master",
|
||||
"source-reference": "8fe7b898b08103c1d6fce64c3e279a7afd61adfc",
|
||||
"commit-date": "1340234971"
|
||||
"source-reference": "ed933dcfa45f00b6bc6d7727007403f3ff429e5a",
|
||||
"commit-date": "1342126277"
|
||||
},
|
||||
{
|
||||
"package": "symfony/monolog-bundle",
|
||||
"version": "dev-master",
|
||||
"source-reference": "7fe7f711bb04b86ad7f45a9e11a7f8cbaf9bc1a5",
|
||||
"source-reference": "v2.1.0-BETA3",
|
||||
"commit-date": "1341078487"
|
||||
},
|
||||
{
|
||||
"package": "symfony/swiftmailer-bundle",
|
||||
"version": "dev-master",
|
||||
"source-reference": "e1d413ce27fd1696bdc82ad9525f1b874664530e",
|
||||
"source-reference": "v2.1.0-BETA3",
|
||||
"commit-date": "1341509614"
|
||||
},
|
||||
{
|
||||
|
@ -116,14 +118,13 @@
|
|||
{
|
||||
"package": "symfony/symfony",
|
||||
"version": "dev-master",
|
||||
"source-reference": "v2.1.0-BETA2",
|
||||
"commit-date": "1341820358"
|
||||
"source-reference": "151b79a6ce3f459e2fa8815cd9f2786eef750993",
|
||||
"commit-date": "1342376835"
|
||||
},
|
||||
{
|
||||
"package": "twig/extensions",
|
||||
"version": "dev-master",
|
||||
"source-reference": "feb6d3f10c411e2631997c0a905aa581c80305c1",
|
||||
"commit-date": "1337599699"
|
||||
"source-reference": "feb6d3f10c411e2631997c0a905aa581c80305c1"
|
||||
},
|
||||
{
|
||||
"package": "twig/twig",
|
||||
|
@ -134,13 +135,11 @@
|
|||
{
|
||||
"package": "twig/twig",
|
||||
"version": "dev-master",
|
||||
"source-reference": "26eb0a2653eade50dffdd31b11ca454232dea8cf",
|
||||
"commit-date": "1341423205"
|
||||
"source-reference": "d45664045194ef62573c153c424508527105041e",
|
||||
"commit-date": "1342424564"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
||||
],
|
||||
"packages-dev": null,
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
|
|
Binary file not shown.
|
@ -21,6 +21,7 @@ return array(
|
|||
'JMS\\SecurityExtraBundle' => $vendorDir . '/jms/security-extra-bundle/',
|
||||
'JMS\\DiExtraBundle' => $vendorDir . '/jms/di-extra-bundle/',
|
||||
'JMS\\AopBundle' => $vendorDir . '/jms/aop-bundle/',
|
||||
'Ivory\\CKEditorBundle' => $vendorDir . '/egeloen/ckeditor-bundle/',
|
||||
'Doctrine\\ORM' => $vendorDir . '/doctrine/orm/lib/',
|
||||
'Doctrine\\DBAL' => $vendorDir . '/doctrine/dbal/lib/',
|
||||
'Doctrine\\Common' => $vendorDir . '/doctrine/common/lib/',
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"name": "jms/metadata",
|
||||
"version": "1.1.1",
|
||||
"version_normalized": "1.1.1.0",
|
||||
"time": "2011-12-30 10:32:49",
|
||||
"time": "2011-12-29 22:32:49",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/metadata",
|
||||
|
@ -47,7 +47,7 @@
|
|||
"name": "jms/cg",
|
||||
"version": "1.0.0",
|
||||
"version_normalized": "1.0.0.0",
|
||||
"time": "2011-12-30 09:40:52",
|
||||
"time": "2011-12-29 21:40:52",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/schmittjoh/cg-library.git",
|
||||
|
@ -89,7 +89,7 @@
|
|||
"version": "1.0.0",
|
||||
"version_normalized": "1.0.0.0",
|
||||
"target-dir": "JMS/AopBundle",
|
||||
"time": "2011-12-30 09:50:26",
|
||||
"time": "2011-12-29 21:50:26",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/JMSAopBundle",
|
||||
|
@ -133,7 +133,7 @@
|
|||
"version": "1.1.0",
|
||||
"version_normalized": "1.1.0.0",
|
||||
"target-dir": "JMS/SecurityExtraBundle",
|
||||
"time": "2011-12-30 13:38:12",
|
||||
"time": "2011-12-30 01:38:12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/JMSSecurityExtraBundle",
|
||||
|
@ -178,7 +178,7 @@
|
|||
"version": "1.0.1",
|
||||
"version_normalized": "1.0.1.0",
|
||||
"target-dir": "JMS/DiExtraBundle",
|
||||
"time": "2012-02-25 05:01:54",
|
||||
"time": "2012-02-24 17:01:54",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/schmittjoh/JMSDiExtraBundle",
|
||||
|
@ -221,7 +221,7 @@
|
|||
"name": "doctrine/common",
|
||||
"version": "2.2.2",
|
||||
"version_normalized": "2.2.2.0",
|
||||
"time": "2012-04-08 03:46:44",
|
||||
"time": "2012-04-07 03:46:44",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/common",
|
||||
|
@ -287,7 +287,7 @@
|
|||
"name": "monolog/monolog",
|
||||
"version": "1.1.0",
|
||||
"version_normalized": "1.1.0.0",
|
||||
"time": "2012-04-18 14:27:40",
|
||||
"time": "2012-04-17 14:27:40",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Seldaek/monolog.git",
|
||||
|
@ -337,7 +337,7 @@
|
|||
"name": "twig/extensions",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-05-16 21:28:19",
|
||||
"time": "2012-05-15 21:28:19",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fabpot/Twig-extensions",
|
||||
|
@ -382,7 +382,7 @@
|
|||
"name": "kriswallsmith/assetic",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-06-08 01:41:54",
|
||||
"time": "2012-06-07 01:41:54",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/kriswallsmith/assetic.git",
|
||||
|
@ -437,285 +437,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sensio/generator-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Sensio/Bundle/GeneratorBundle",
|
||||
"time": "2012-06-15 18:40:45",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sensio/SensioGeneratorBundle",
|
||||
"reference": "43ed45c48db18e4a0e48aec0c098f42e56e22d36"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/sensio/SensioGeneratorBundle/zipball/43ed45c48db18e4a0e48aec0c098f42e56e22d36",
|
||||
"reference": "43ed45c48db18e4a0e48aec0c098f42e56e22d36",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"symfony/framework-bundle": "2.1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/doctrine-bridge": "2.1.*",
|
||||
"doctrine/orm": ">=2.1,<2.4-dev",
|
||||
"twig/twig": ">=1.8,<2.0-dev"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/doctrine-bundle": "to generate entities and their crud controller"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "This bundle generates code for you",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Sensio\\Bundle\\GeneratorBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/assetic-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Symfony/Bundle/AsseticBundle",
|
||||
"time": "2012-06-16 23:29:31",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/AsseticBundle",
|
||||
"reference": "8fe7b898b08103c1d6fce64c3e279a7afd61adfc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/AsseticBundle/zipball/8fe7b898b08103c1d6fce64c3e279a7afd61adfc",
|
||||
"reference": "8fe7b898b08103c1d6fce64c3e279a7afd61adfc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"symfony/framework-bundle": "2.1.*",
|
||||
"kriswallsmith/assetic": "1.1.*"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/twig-bundle": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kris Wallsmith",
|
||||
"email": "kris.wallsmith@gmail.com",
|
||||
"homepage": "http://kriswallsmith.net/",
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Integrates Assetic into Symfony2",
|
||||
"homepage": "https://github.com/symfony/AsseticBundle",
|
||||
"keywords": [
|
||||
"assets",
|
||||
"compression",
|
||||
"minification"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Bundle\\AsseticBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/monolog-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Symfony/Bundle/MonologBundle",
|
||||
"time": "2012-06-28 15:48:07",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/MonologBundle",
|
||||
"reference": "7fe7f711bb04b86ad7f45a9e11a7f8cbaf9bc1a5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/MonologBundle/zipball/7fe7f711bb04b86ad7f45a9e11a7f8cbaf9bc1a5",
|
||||
"reference": "7fe7f711bb04b86ad7f45a9e11a7f8cbaf9bc1a5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"monolog/monolog": "1.*",
|
||||
"symfony/monolog-bridge": "2.1.*",
|
||||
"symfony/dependency-injection": "2.1.*",
|
||||
"symfony/config": "2.1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/yaml": "2.1.*",
|
||||
"symfony/config": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"email": null,
|
||||
"homepage": "http://symfony.com/contributors",
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Symfony MonologBundle",
|
||||
"homepage": "http://symfony.com",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Bundle\\MonologBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sensio/framework-extra-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Sensio/Bundle/FrameworkExtraBundle",
|
||||
"time": "2012-06-29 05:03:39",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sensio/SensioFrameworkExtraBundle",
|
||||
"reference": "4f54e5d5fb3b54fb107892684018f3704934c48d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/sensio/SensioFrameworkExtraBundle/zipball/4f54e5d5fb3b54fb107892684018f3704934c48d",
|
||||
"reference": "4f54e5d5fb3b54fb107892684018f3704934c48d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/common": ">=2.1,<2.4-dev",
|
||||
"symfony/framework-bundle": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "This bundle provides a way to configure your controllers with annotations",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"controllers"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Sensio\\Bundle\\FrameworkExtraBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-07-03 15:33:25",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/fabpot/Twig.git",
|
||||
"reference": "26eb0a2653eade50dffdd31b11ca454232dea8cf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/fabpot/Twig/zipball/26eb0a2653eade50dffdd31b11ca454232dea8cf",
|
||||
"reference": "26eb0a2653eade50dffdd31b11ca454232dea8cf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"BSD-3"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "http://twig.sensiolabs.org",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_": "lib/"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "doctrine/doctrine-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Doctrine/Bundle/DoctrineBundle",
|
||||
"time": "2012-07-03 10:42:17",
|
||||
"time": "2012-07-02 10:42:17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/doctrine/DoctrineBundle.git",
|
||||
|
@ -785,70 +512,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/swiftmailer-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Symfony/Bundle/SwiftmailerBundle",
|
||||
"time": "2012-07-04 15:33:34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/SwiftmailerBundle",
|
||||
"reference": "e1d413ce27fd1696bdc82ad9525f1b874664530e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/SwiftmailerBundle/zipball/e1d413ce27fd1696bdc82ad9525f1b874664530e",
|
||||
"reference": "e1d413ce27fd1696bdc82ad9525f1b874664530e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"symfony/swiftmailer-bridge": "2.1.*",
|
||||
"swiftmailer/swiftmailer": ">=4.2.0,<4.3-dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/dependency-injection": "2.1.*",
|
||||
"symfony/http-kernel": "2.1.*",
|
||||
"symfony/config": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"email": null,
|
||||
"homepage": "http://symfony.com/contributors",
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Symfony SwiftmailerBundle",
|
||||
"homepage": "http://symfony.com",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Bundle\\SwiftmailerBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "doctrine/orm",
|
||||
"version": "2.2.x-dev",
|
||||
"version_normalized": "2.2.9999999.9999999-dev",
|
||||
"time": "2012-07-07 07:48:00",
|
||||
"time": "2012-07-06 07:48:00",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/doctrine/doctrine2.git",
|
||||
|
@ -909,66 +577,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-07-08 09:21:00",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/swiftmailer/swiftmailer.git",
|
||||
"reference": "f51b5f33c83b48faea75f1285f99a2e8f1c66f75"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/swiftmailer/swiftmailer/zipball/f51b5f33c83b48faea75f1285f99a2e8f1c66f75",
|
||||
"reference": "f51b5f33c83b48faea75f1285f99a2e8f1c66f75",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"LGPL"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Chris Corbyn",
|
||||
"email": "",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Swiftmailer, free feature-rich PHP mailer",
|
||||
"homepage": "http://swiftmailer.org",
|
||||
"keywords": [
|
||||
"mail",
|
||||
"mailer"
|
||||
],
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/swift_required.php"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "doctrine/dbal",
|
||||
"version": "2.2.x-dev",
|
||||
"version_normalized": "2.2.9999999.9999999-dev",
|
||||
"time": "2012-07-08 18:30:35",
|
||||
"time": "2012-07-07 18:30:35",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/doctrine/dbal",
|
||||
|
@ -1030,25 +643,456 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/symfony",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-07-09 05:52:38",
|
||||
"name": "egeloen/ckeditor-bundle",
|
||||
"version": "2.0.x-dev",
|
||||
"version_normalized": "2.0.9999999.9999999-dev",
|
||||
"target-dir": "Ivory/CKEditorBundle",
|
||||
"time": "2012-05-16 18:38:27",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/symfony/symfony.git",
|
||||
"reference": "v2.1.0-BETA2"
|
||||
"url": "https://github.com/egeloen/IvoryCKEditorBundle",
|
||||
"reference": "ca9d4a631577d7195c6517dd89ae8a3cc02b85ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/symfony/zipball/v2.1.0-BETA2",
|
||||
"reference": "v2.1.0-BETA2",
|
||||
"url": "https://github.com/egeloen/IvoryCKEditorBundle/zipball/ca9d4a631577d7195c6517dd89ae8a3cc02b85ba",
|
||||
"reference": "ca9d4a631577d7195c6517dd89ae8a3cc02b85ba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"symfony/framework-bundle": "2.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Eric GELOEN",
|
||||
"email": "geloen.eric@gmail.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Provides a CKEditor integration for your Symfony2 Project.",
|
||||
"keywords": [
|
||||
"CKEditor"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Ivory\\CKEditorBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sensio/generator-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Sensio/Bundle/GeneratorBundle",
|
||||
"time": "2012-07-13 00:04:48",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sensio/SensioGeneratorBundle",
|
||||
"reference": "c17dbddefe517e3adfcbeaa1ab7cef3e572d29c6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/sensio/SensioGeneratorBundle/zipball/c17dbddefe517e3adfcbeaa1ab7cef3e572d29c6",
|
||||
"reference": "c17dbddefe517e3adfcbeaa1ab7cef3e572d29c6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"symfony/framework-bundle": "2.1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/doctrine-bridge": "2.1.*",
|
||||
"doctrine/orm": ">=2.1,<2.4-dev",
|
||||
"twig/twig": ">=1.8,<2.0-dev"
|
||||
},
|
||||
"suggest": {
|
||||
"doctrine/doctrine-bundle": "to generate entities and their crud controller"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "This bundle generates code for you",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Sensio\\Bundle\\GeneratorBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/assetic-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Symfony/Bundle/AsseticBundle",
|
||||
"time": "2012-07-12 06:51:17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/AsseticBundle",
|
||||
"reference": "ed933dcfa45f00b6bc6d7727007403f3ff429e5a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/AsseticBundle/zipball/ed933dcfa45f00b6bc6d7727007403f3ff429e5a",
|
||||
"reference": "ed933dcfa45f00b6bc6d7727007403f3ff429e5a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"symfony/framework-bundle": "2.1.*",
|
||||
"kriswallsmith/assetic": "1.1.*"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/twig-bundle": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kris Wallsmith",
|
||||
"email": "kris.wallsmith@gmail.com",
|
||||
"homepage": "http://kriswallsmith.net/",
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Integrates Assetic into Symfony2",
|
||||
"homepage": "https://github.com/symfony/AsseticBundle",
|
||||
"keywords": [
|
||||
"assets",
|
||||
"compression",
|
||||
"minification"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Bundle\\AsseticBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/monolog-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Symfony/Bundle/MonologBundle",
|
||||
"time": "2012-06-30 05:48:07",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/MonologBundle",
|
||||
"reference": "v2.1.0-BETA3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/MonologBundle/zipball/v2.1.0-BETA3",
|
||||
"reference": "v2.1.0-BETA3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"monolog/monolog": "1.*",
|
||||
"symfony/monolog-bridge": "2.1.*",
|
||||
"symfony/dependency-injection": "2.1.*",
|
||||
"symfony/config": "2.1.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/yaml": "2.1.*",
|
||||
"symfony/config": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"email": null,
|
||||
"homepage": "http://symfony.com/contributors",
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Symfony MonologBundle",
|
||||
"homepage": "http://symfony.com",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Bundle\\MonologBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sensio/framework-extra-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Sensio/Bundle/FrameworkExtraBundle",
|
||||
"time": "2012-07-11 23:13:52",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sensio/SensioFrameworkExtraBundle",
|
||||
"reference": "e9ac8f1a911ed29e30296c7f1549f53d4c94eddf"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/sensio/SensioFrameworkExtraBundle/zipball/e9ac8f1a911ed29e30296c7f1549f53d4c94eddf",
|
||||
"reference": "e9ac8f1a911ed29e30296c7f1549f53d4c94eddf",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/common": ">=2.1,<2.4-dev",
|
||||
"symfony/framework-bundle": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "This bundle provides a way to configure your controllers with annotations",
|
||||
"keywords": [
|
||||
"annotations",
|
||||
"controllers"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Sensio\\Bundle\\FrameworkExtraBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-07-15 23:42:44",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/fabpot/Twig.git",
|
||||
"reference": "d45664045194ef62573c153c424508527105041e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/fabpot/Twig/zipball/d45664045194ef62573c153c424508527105041e",
|
||||
"reference": "d45664045194ef62573c153c424508527105041e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.9-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"BSD-3"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "http://twig.sensiolabs.org",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_": "lib/"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/swiftmailer-bundle",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Symfony/Bundle/SwiftmailerBundle",
|
||||
"time": "2012-07-05 11:33:34",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/SwiftmailerBundle",
|
||||
"reference": "v2.1.0-BETA3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/SwiftmailerBundle/zipball/v2.1.0-BETA3",
|
||||
"reference": "v2.1.0-BETA3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"symfony/swiftmailer-bridge": "2.1.*",
|
||||
"swiftmailer/swiftmailer": ">=4.2.0,<4.3-dev"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/dependency-injection": "2.1.*",
|
||||
"symfony/http-kernel": "2.1.*",
|
||||
"symfony/config": "2.1.*"
|
||||
},
|
||||
"type": "symfony-bundle",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"email": null,
|
||||
"homepage": "http://symfony.com/contributors",
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Symfony SwiftmailerBundle",
|
||||
"homepage": "http://symfony.com",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Bundle\\SwiftmailerBundle": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-07-13 12:47:17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/swiftmailer/swiftmailer.git",
|
||||
"reference": "8b2aa953f87da228ba413e8fb1372e49c1374050"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/swiftmailer/swiftmailer/zipball/8b2aa953f87da228ba413e8fb1372e49c1374050",
|
||||
"reference": "8b2aa953f87da228ba413e8fb1372e49c1374050",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.2-dev"
|
||||
}
|
||||
},
|
||||
"installation-source": "source",
|
||||
"license": [
|
||||
"LGPL"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
},
|
||||
{
|
||||
"name": "Chris Corbyn",
|
||||
"email": "",
|
||||
"homepage": null,
|
||||
"role": null
|
||||
}
|
||||
],
|
||||
"description": "Swiftmailer, free feature-rich PHP mailer",
|
||||
"homepage": "http://swiftmailer.org",
|
||||
"keywords": [
|
||||
"mail",
|
||||
"mailer"
|
||||
],
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/swift_required.php"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "symfony/symfony",
|
||||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"time": "2012-07-15 16:27:15",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/symfony/symfony.git",
|
||||
"reference": "151b79a6ce3f459e2fa8815cd9f2786eef750993"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/symfony/symfony/zipball/151b79a6ce3f459e2fa8815cd9f2786eef750993",
|
||||
"reference": "151b79a6ce3f459e2fa8815cd9f2786eef750993",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"twig/twig": ">=1.8,<2.0-dev",
|
||||
"doctrine/common": ">2.2,<2.4-dev"
|
||||
"doctrine/common": ">2.2,<2.4-dev",
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"replace": {
|
||||
"symfony/doctrine-bridge": "self.version",
|
||||
|
@ -1135,16 +1179,16 @@
|
|||
"version": "dev-master",
|
||||
"version_normalized": "9999999-dev",
|
||||
"target-dir": "Sensio/Bundle/DistributionBundle",
|
||||
"time": "2012-07-08 08:02:21",
|
||||
"time": "2012-07-15 10:24:10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sensio/SensioDistributionBundle",
|
||||
"reference": "9a7dbd867fd5061e4bfd660a175aa66122f53d25"
|
||||
"reference": "5886adae1613c0a72fbb95259a83ae798e86c0d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/sensio/SensioDistributionBundle/zipball/9a7dbd867fd5061e4bfd660a175aa66122f53d25",
|
||||
"reference": "9a7dbd867fd5061e4bfd660a175aa66122f53d25",
|
||||
"url": "https://github.com/sensio/SensioDistributionBundle/zipball/5886adae1613c0a72fbb95259a83ae798e86c0d3",
|
||||
"reference": "5886adae1613c0a72fbb95259a83ae798e86c0d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ca9d4a631577d7195c6517dd89ae8a3cc02b85ba
|
|
@ -31,7 +31,7 @@ class ScriptHandler
|
|||
return;
|
||||
}
|
||||
|
||||
static::executeBuildBootstrap($appDir);
|
||||
static::executeBuildBootstrap($appDir, $options['process-timeout']);
|
||||
}
|
||||
|
||||
public static function clearCache($event)
|
||||
|
@ -45,7 +45,7 @@ class ScriptHandler
|
|||
return;
|
||||
}
|
||||
|
||||
static::executeCommand($event, $appDir, 'cache:clear --no-warmup');
|
||||
static::executeCommand($event, $appDir, 'cache:clear --no-warmup', $options['process-timeout']);
|
||||
}
|
||||
|
||||
public static function installAssets($event)
|
||||
|
@ -123,7 +123,7 @@ namespace { return \$loader; }
|
|||
", substr(file_get_contents($file), 5)));
|
||||
}
|
||||
|
||||
protected static function executeCommand($event, $appDir, $cmd)
|
||||
protected static function executeCommand($event, $appDir, $cmd, $timeout = 300)
|
||||
{
|
||||
$php = escapeshellarg(self::getPhp());
|
||||
$console = escapeshellarg($appDir.'/console');
|
||||
|
@ -131,17 +131,17 @@ namespace { return \$loader; }
|
|||
$console.= ' --ansi';
|
||||
}
|
||||
|
||||
$process = new Process($php.' '.$console.' '.$cmd, null, null, null, 300);
|
||||
$process = new Process($php.' '.$console.' '.$cmd, null, null, null, $timeout);
|
||||
$process->run(function ($type, $buffer) { echo $buffer; });
|
||||
}
|
||||
|
||||
protected static function executeBuildBootstrap($appDir)
|
||||
protected static function executeBuildBootstrap($appDir, $timeout = 300)
|
||||
{
|
||||
$php = escapeshellarg(self::getPhp());
|
||||
$cmd = escapeshellarg(__DIR__.'/../Resources/bin/build_bootstrap.php');
|
||||
$appDir = escapeshellarg($appDir);
|
||||
|
||||
$process = new Process($php.' '.$cmd.' '.$appDir, null, null, null, 300);
|
||||
$process = new Process($php.' '.$cmd.' '.$appDir, null, null, null, $timeout);
|
||||
$process->run(function ($type, $buffer) { echo $buffer; });
|
||||
}
|
||||
|
||||
|
@ -155,6 +155,8 @@ namespace { return \$loader; }
|
|||
|
||||
$options['symfony-assets-install'] = getenv('SYMFONY_ASSETS_INSTALL') ?: $options['symfony-assets-install'];
|
||||
|
||||
$options['process-timeout'] = $event->getComposer()->getConfig()->get('process-timeout');
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\DistributionBundle\Diff;
|
||||
|
||||
/**
|
||||
* Computes a Diff between files (line by line).
|
||||
*
|
||||
* Implements the Longest common subsequence problem algorithm.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Diff
|
||||
{
|
||||
private $diff;
|
||||
|
||||
public function __construct($str1, $str2)
|
||||
{
|
||||
$lines1 = explode("\n", $str1);
|
||||
$lines2 = explode("\n", $str2);
|
||||
|
||||
$this->diff = $this->computeDiff($this->computeLcs($lines1, $lines2), $lines1, $lines2, count($lines1) - 1, count($lines2) - 1);
|
||||
}
|
||||
|
||||
public function getDiff()
|
||||
{
|
||||
$diff = array();
|
||||
for ($i = 0, $max = count($this->diff); $i < $max; $i++) {
|
||||
if ('' != $this->diff[$i][0]) {
|
||||
$diff[] = array('@', sprintf(' Line %s', $this->diff[$i][2]));
|
||||
|
||||
do {
|
||||
$diff[] = $this->diff[$i++];
|
||||
} while ('' != $this->diff[$i][0]);
|
||||
}
|
||||
}
|
||||
|
||||
return $diff;
|
||||
}
|
||||
|
||||
public function computeDiff(array $c, array $lines1, array $lines2, $i, $j)
|
||||
{
|
||||
$diff = array();
|
||||
|
||||
if ($i > -1 && $j > -1 && $lines1[$i] == $lines2[$j]) {
|
||||
$diff = array_merge($diff, $this->computeDiff($c, $lines1, $lines2, $i - 1, $j - 1));
|
||||
$diff[] = array('', $lines1[$i], $i, $j);
|
||||
} else {
|
||||
if ($j > -1 && ($i == -1 || $c[$i][$j - 1] >= $c[$i - 1][$j])) {
|
||||
$diff = array_merge($diff, $this->computeDiff($c, $lines1, $lines2, $i, $j - 1));
|
||||
$diff[] = array('+', $lines2[$j], $i, $j);
|
||||
} elseif ($i > -1 && ($j == -1 || $c[$i][$j - 1] < $c[$i - 1][$j])) {
|
||||
$diff = array_merge($diff, $this->computeDiff($c, $lines1, $lines2, $i - 1, $j));
|
||||
$diff[] = array('-', $lines1[$i], $i, $j);
|
||||
}
|
||||
}
|
||||
|
||||
return $diff;
|
||||
}
|
||||
|
||||
private function computeLcs(array $lines1, array $lines2)
|
||||
{
|
||||
for ($i = -1, $len1 = count($lines1); $i < $len1; $i++) {
|
||||
for ($j = -1, $len2 = count($lines2); $j < $len2; $j++) {
|
||||
$c[$i][$j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $len1; $i++) {
|
||||
for ($j = 0; $j < $len2; $j++) {
|
||||
if ($lines1[$i] == $lines2[$j]) {
|
||||
$c[$i][$j] = $c[$i - 1][$j - 1] + 1;
|
||||
} else {
|
||||
$c[$i][$j] = max($c[$i][$j - 1], $c[$i - 1][$j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
}
|
|
@ -429,11 +429,11 @@ class SymfonyRequirements extends RequirementCollection
|
|||
);
|
||||
|
||||
if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) {
|
||||
$this->addRequirement(
|
||||
(in_array(date_default_timezone_get(), DateTimeZone::listIdentifiers())),
|
||||
sprintf('Default timezone is deprecated (%s)', date_default_timezone_get()),
|
||||
'Fix your <strong>php.ini</strong> file (list of deprecated timezones http://us.php.net/manual/en/timezones.others.php).'
|
||||
);
|
||||
$this->addRequirement(
|
||||
(in_array(date_default_timezone_get(), DateTimeZone::listIdentifiers())),
|
||||
sprintf('Default timezone "%s" is not supported by your installation of PHP', date_default_timezone_get()),
|
||||
'Fix your <strong>php.ini</strong> file (check for typos and have a look at the list of deprecated timezones http://php.net/manual/en/timezones.others.php).'
|
||||
);
|
||||
}
|
||||
|
||||
$this->addRequirement(
|
||||
|
@ -492,6 +492,12 @@ class SymfonyRequirements extends RequirementCollection
|
|||
|
||||
/* optional recommendations follow */
|
||||
|
||||
$this->addRecommendation(
|
||||
version_compare($installedPhpVersion, '5.3.4', '>='),
|
||||
sprintf('Your project might not work properly ("Notice: Trying to get property of non-object") due to the PHP bug #52083 before PHP 5.3.4 (%s installed)', $installedPhpVersion),
|
||||
'Install PHP 5.3.4 or newer'
|
||||
);
|
||||
|
||||
$this->addRecommendation(
|
||||
version_compare($installedPhpVersion, '5.3.8', '>='),
|
||||
sprintf('Annotations might not work properly due to the PHP bug #55156 before PHP 5.3.8 (%s installed)', $installedPhpVersion),
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\DistributionBundle\Upgrade;
|
||||
|
||||
use Sensio\Bundle\DistributionBundle\Diff\Diff;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Upgrade class.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Upgrade
|
||||
{
|
||||
public function outputConsoleDiff(OutputInterface $output, $file1, $file2)
|
||||
{
|
||||
if (is_file($file1)) {
|
||||
$file1 = realpath($file1);
|
||||
$str1 = file_get_contents($file1);
|
||||
} else {
|
||||
$str1 = '';
|
||||
}
|
||||
|
||||
if (!is_file($file2)) {
|
||||
throw new \RuntimeException(sprintf('The skeleton file "%s" does not exist.', $file2));
|
||||
}
|
||||
$file2 = realpath($file2);
|
||||
$str2 = file_get_contents($file2);
|
||||
|
||||
$diff = new Diff($str1, $str2);
|
||||
|
||||
$output->writeln(sprintf('--- %s', $file1));
|
||||
$output->writeln(sprintf('+++ %s', $file2));
|
||||
foreach ($diff->getDiff() as $line) {
|
||||
if ('+' == $line[0]) {
|
||||
$format = '<fg=green>+%s</>';
|
||||
} elseif ('-' == $line[0]) {
|
||||
$format = '<fg=red>-%s</>';
|
||||
} elseif ('@' == $line[0]) {
|
||||
$format = '<fg=cyan>@%s</>';
|
||||
} else {
|
||||
$format = ' %s';
|
||||
}
|
||||
|
||||
$output->writeln(sprintf($format, $line[1]));
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
}
|
||||
}
|
4
vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/.gitignore
vendored
Normal file
4
vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
coverage
|
||||
phpunit.xml
|
||||
vendor
|
||||
composer.lock
|
6
vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/CHANGELOG-2.1.md
vendored
Normal file
6
vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/CHANGELOG-2.1.md
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
CHANGELOG for 2.1.x
|
||||
===================
|
||||
|
||||
* added the possibility to configure the id name for the Doctrine converter via the id option
|
||||
* [BC break] The ParamConverterInterface::apply() method now must return a
|
||||
Boolean value indicating if a conversion was done.
|
|
@ -74,6 +74,19 @@ option::
|
|||
{
|
||||
}
|
||||
|
||||
This also allows you to have multiple converters in one action::
|
||||
|
||||
/**
|
||||
* @Route("/blog/{id}/comments/{comment_id}")
|
||||
* @ParamConverter("comment", class="SensioBlogBundle:Comment", options={"id" = "comment_id"})
|
||||
*/
|
||||
public function showAction(Post $post, Comment $comment)
|
||||
{
|
||||
}
|
||||
|
||||
In the example above, the post parameter is handled automatically, but the comment is
|
||||
configured with the annotation since they can not both follow the default convention.
|
||||
|
||||
Creating a Converter
|
||||
--------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\Configuration;
|
||||
|
||||
class ConfigurationAnnotationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException RuntimeException
|
||||
*/
|
||||
public function testUndefinedSetterThrowsException()
|
||||
{
|
||||
$this->getMockForAbstractClass('Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationAnnotation', array(
|
||||
array(
|
||||
'doesNotExists' => true,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\EventListener\CacheListener;
|
||||
|
||||
class CacheListenerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->listener = new CacheListener();
|
||||
$this->response = new Response();
|
||||
$this->cache = new Cache(array());
|
||||
$this->request = $this->createRequest($this->cache);
|
||||
$this->event = $this->createEventMock($this->request, $this->response);
|
||||
}
|
||||
|
||||
public function testWontReassignResponseWhenResponseIsUnsuccessful()
|
||||
{
|
||||
$this->event
|
||||
->expects($this->never())
|
||||
->method('setResponse')
|
||||
;
|
||||
|
||||
$this->response->setStatusCode(404);
|
||||
|
||||
$this->assertInternalType('null', $this->listener->onKernelResponse($this->event));
|
||||
}
|
||||
|
||||
public function testWontReassignResponseWhenNoConfigurationIsPresent()
|
||||
{
|
||||
$this->event
|
||||
->expects($this->never())
|
||||
->method('setResponse')
|
||||
;
|
||||
|
||||
$this->request->attributes->remove('_cache');
|
||||
|
||||
$this->assertInternalType('null', $this->listener->onKernelResponse($this->event));
|
||||
}
|
||||
|
||||
public function testResponseIsPublicIfConfigurationIsPublic()
|
||||
{
|
||||
$request = $this->createRequest(new Cache(array(
|
||||
'public' => true,
|
||||
)));
|
||||
|
||||
$this->listener->onKernelResponse($this->createEventMock($request, $this->response));
|
||||
|
||||
$this->assertTrue($this->response->headers->hasCacheControlDirective('public'));
|
||||
$this->assertFalse($this->response->headers->hasCacheControlDirective('private'));
|
||||
}
|
||||
|
||||
public function testConfigurationAttributesAreSetOnResponse()
|
||||
{
|
||||
$this->assertInternalType('null', $this->response->getMaxAge());
|
||||
$this->assertInternalType('null', $this->response->getExpires());
|
||||
$this->assertFalse($this->response->headers->hasCacheControlDirective('s-maxage'));
|
||||
|
||||
$this->request->attributes->set('_cache', new Cache(array(
|
||||
'expires' => 'tomorrow',
|
||||
'smaxage' => '15',
|
||||
'maxage' => '15',
|
||||
)));
|
||||
|
||||
$this->listener->onKernelResponse($this->event);
|
||||
|
||||
$this->assertEquals('15', $this->response->getMaxAge());
|
||||
$this->assertEquals('15', $this->response->headers->getCacheControlDirective('s-maxage'));
|
||||
$this->assertInstanceOf('DateTime', $this->response->getExpires());
|
||||
}
|
||||
|
||||
protected function createRequest(Cache $cache = null)
|
||||
{
|
||||
return new Request(array(), array(), array(
|
||||
'_cache' => $cache,
|
||||
));
|
||||
}
|
||||
|
||||
protected function createEventMock(Request $request, Response $response)
|
||||
{
|
||||
$event = $this->getMock('Symfony\Component\HttpKernel\Event\FilterResponseEvent', array(), array(), '', null);
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getRequest')
|
||||
->will($this->returnValue($request))
|
||||
;
|
||||
|
||||
$event
|
||||
->expects($this->any())
|
||||
->method('getResponse')
|
||||
->will($this->returnValue($response))
|
||||
;
|
||||
|
||||
return $event;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\EventListener\ControllerListener;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener\Fixture\FooControllerCacheAtClass;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener\Fixture\FooControllerCacheAtClassAndMethod;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener\Fixture\FooControllerCacheAtMethod;
|
||||
|
||||
use Doctrine\Common\Annotations\AnnotationReader;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
|
||||
class ControllerListenerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->listener = new ControllerListener(new AnnotationReader());
|
||||
$this->request = $this->createRequest();
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->listener = null;
|
||||
$this->request = null;
|
||||
}
|
||||
|
||||
public function testCacheAnnotationAtMethod()
|
||||
{
|
||||
$controller = new FooControllerCacheAtMethod();
|
||||
|
||||
$this->event = $this->getFilterControllerEvent(array($controller, 'barAction'), $this->request);
|
||||
$this->listener->onKernelController($this->event);
|
||||
|
||||
$this->assertNotNull($this->getReadedCache());
|
||||
$this->assertEquals(FooControllerCacheAtMethod::METHOD_SMAXAGE, $this->getReadedCache()->getSMaxAge());
|
||||
}
|
||||
|
||||
public function testCacheAnnotationAtClass()
|
||||
{
|
||||
$controller = new FooControllerCacheAtClass();
|
||||
$this->event = $this->getFilterControllerEvent(array($controller, 'barAction'), $this->request);
|
||||
$this->listener->onKernelController($this->event);
|
||||
|
||||
$this->assertNotNull($this->getReadedCache());
|
||||
$this->assertEquals(FooControllerCacheAtClass::CLASS_SMAXAGE, $this->getReadedCache()->getSMaxAge());
|
||||
}
|
||||
|
||||
public function testCacheAnnotationAtClassAndMethod()
|
||||
{
|
||||
$controller = new FooControllerCacheAtClassAndMethod();
|
||||
$this->event = $this->getFilterControllerEvent(array($controller, 'barAction'), $this->request);
|
||||
$this->listener->onKernelController($this->event);
|
||||
|
||||
$this->assertNotNull($this->getReadedCache());
|
||||
$this->assertEquals(FooControllerCacheAtClassAndMethod::METHOD_SMAXAGE, $this->getReadedCache()->getSMaxAge());
|
||||
|
||||
$this->event = $this->getFilterControllerEvent(array($controller, 'bar2Action'), $this->request);
|
||||
$this->listener->onKernelController($this->event);
|
||||
|
||||
$this->assertNotNull($this->getReadedCache());
|
||||
$this->assertEquals(FooControllerCacheAtClassAndMethod::CLASS_SMAXAGE, $this->getReadedCache()->getSMaxAge());
|
||||
}
|
||||
|
||||
protected function createRequest(Cache $cache = null)
|
||||
{
|
||||
return new Request(array(), array(), array(
|
||||
'_cache' => $cache,
|
||||
));
|
||||
}
|
||||
|
||||
protected function getFilterControllerEvent($controller, Request $request)
|
||||
{
|
||||
$mockKernel = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\Kernel', array('', ''));
|
||||
|
||||
return new FilterControllerEvent($mockKernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST);
|
||||
}
|
||||
|
||||
protected function getReadedCache()
|
||||
{
|
||||
return $this->request->attributes->get('_cache');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener\Fixture;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
|
||||
/**
|
||||
* @Cache(smaxage="20")
|
||||
*/
|
||||
class FooControllerCacheAtClass
|
||||
{
|
||||
const CLASS_SMAXAGE = 20;
|
||||
|
||||
public function barAction()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener\Fixture;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
|
||||
/**
|
||||
* @Cache(smaxage="20")
|
||||
*/
|
||||
class FooControllerCacheAtClassAndMethod
|
||||
{
|
||||
const CLASS_SMAXAGE = 20;
|
||||
const METHOD_SMAXAGE = 15;
|
||||
|
||||
/**
|
||||
* @Cache(smaxage="15")
|
||||
*/
|
||||
public function barAction()
|
||||
{
|
||||
}
|
||||
|
||||
public function bar2Action()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\EventListener\Fixture;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
|
||||
|
||||
class FooControllerCacheAtMethod
|
||||
{
|
||||
const METHOD_SMAXAGE = 15;
|
||||
|
||||
/**
|
||||
* @Cache(smaxage="15")
|
||||
*/
|
||||
public function barAction()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\Request\ParamConverter;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\DoctrineParamConverter;
|
||||
|
||||
class DoctrineParamConverterTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var Doctrine\Common\Persistence\ManagerRegistry
|
||||
*/
|
||||
private $manager;
|
||||
|
||||
/**
|
||||
* @var DoctrineParamConverter
|
||||
*/
|
||||
private $converter;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
if (!interface_exists('Doctrine\Common\Persistence\ManagerRegistry')) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$this->manager = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
|
||||
$this->converter = new DoctrineParamConverter($this->manager);
|
||||
}
|
||||
|
||||
public function createConfiguration($class = null, array $options = null)
|
||||
{
|
||||
$config = $this->getMock(
|
||||
'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface', array(
|
||||
'getClass', 'getAliasName', 'getOptions'
|
||||
));
|
||||
if ($options !== null) {
|
||||
$config->expects($this->once())
|
||||
->method('getOptions')
|
||||
->will($this->returnValue($options));
|
||||
}
|
||||
if ($class !== null) {
|
||||
$config->expects($this->any())
|
||||
->method('getClass')
|
||||
->will($this->returnValue($class));
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
public function testApplyWithNoIdAndData()
|
||||
{
|
||||
$request = new Request();
|
||||
$config = $this->createConfiguration(null, array());
|
||||
$objectManager = $this->getMock('Doctrine\Common\Persistence\ObjectManager');
|
||||
|
||||
$this->manager->expects($this->never())->method('find');
|
||||
$this->manager->expects($this->once())
|
||||
->method('getManager')
|
||||
->will($this->returnValue($objectManager));
|
||||
|
||||
$this->setExpectedException('LogicException');
|
||||
$this->converter->apply($request, $config);
|
||||
}
|
||||
|
||||
public function testSupports()
|
||||
{
|
||||
$config = $this->createConfiguration('stdClass', array());
|
||||
$metadataFactory = $this->getMock('Doctrine\Common\Persistence\Mapping\ClassMetadataFactory');
|
||||
$metadataFactory->expects($this->once())
|
||||
->method('isTransient')
|
||||
->with($this->equalTo('stdClass'))
|
||||
->will($this->returnValue( false ));
|
||||
|
||||
$objectManager = $this->getMock('Doctrine\Common\Persistence\ObjectManager');
|
||||
$objectManager->expects($this->once())
|
||||
->method('getMetadataFactory')
|
||||
->will($this->returnValue($metadataFactory));
|
||||
|
||||
$this->manager->expects($this->once())
|
||||
->method('getManager')
|
||||
->will($this->returnValue($objectManager));
|
||||
|
||||
$ret = $this->converter->supports($config);
|
||||
|
||||
$this->assertTrue($ret, "Should be supported");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Tests\Request\ParamConverter;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterManager;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class ParamConverterManagerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$this->manager = new ParamConverterManager();
|
||||
}
|
||||
|
||||
public function testPriorities()
|
||||
{
|
||||
$this->assertEquals(array(), $this->manager->all());
|
||||
|
||||
$high = $this->createParamConverterMock();
|
||||
$low = $this->createParamConverterMock();
|
||||
|
||||
$this->manager->add($low);
|
||||
$this->manager->add($high, 10);
|
||||
|
||||
$this->assertEquals(array(
|
||||
$high,
|
||||
$low,
|
||||
), $this->manager->all());
|
||||
}
|
||||
|
||||
public function testApply()
|
||||
{
|
||||
$supported = $this->createParamConverterMock();
|
||||
$supported
|
||||
->expects($this->once())
|
||||
->method('supports')
|
||||
->will($this->returnValue(true))
|
||||
;
|
||||
$supported
|
||||
->expects($this->once())
|
||||
->method('apply')
|
||||
->will($this->returnValue(false))
|
||||
;
|
||||
|
||||
$invalid = $this->createParamConverterMock();
|
||||
$invalid
|
||||
->expects($this->once())
|
||||
->method('supports')
|
||||
->will($this->returnValue(false))
|
||||
;
|
||||
$invalid
|
||||
->expects($this->never())
|
||||
->method('apply')
|
||||
;
|
||||
|
||||
$configurations = array(
|
||||
new Configuration\ParamConverter(array(
|
||||
'name' => 'var',
|
||||
)),
|
||||
);
|
||||
|
||||
$this->manager->add($supported);
|
||||
$this->manager->add($invalid);
|
||||
$this->manager->apply(new Request(), $configurations);
|
||||
}
|
||||
|
||||
public function testApplyNotCalledOnAlreadyConvertedObjects()
|
||||
{
|
||||
|
||||
$converter = $this->createParamConverterMock();
|
||||
$converter
|
||||
->expects($this->never())
|
||||
->method('supports')
|
||||
;
|
||||
|
||||
$converter
|
||||
->expects($this->never())
|
||||
->method('apply')
|
||||
;
|
||||
|
||||
$this->manager->add($converter);
|
||||
|
||||
$request = new Request();
|
||||
$request->attributes->set('converted', new \stdClass);
|
||||
|
||||
$configuration = new Configuration\ParamConverter(array(
|
||||
'name' => 'converted',
|
||||
'class' => 'stdClass',
|
||||
));
|
||||
|
||||
$this->manager->apply($request, array($configuration));
|
||||
}
|
||||
|
||||
protected function createParamConverterMock()
|
||||
{
|
||||
return $this->getMock('Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface');
|
||||
}
|
||||
}
|
20
vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/phpunit.xml.dist
vendored
Normal file
20
vendor/sensio/framework-extra-bundle/Sensio/Bundle/FrameworkExtraBundle/phpunit.xml.dist
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="./vendor/autoload.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="SensioFrameworkExtraBundle">
|
||||
<directory suffix="Test.php">./Tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./</directory>
|
||||
<exclude>
|
||||
<directory>./Resources</directory>
|
||||
<directory>./Tests</directory>
|
||||
<directory>./vendor</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
|
@ -0,0 +1,3 @@
|
|||
phpunit.xml
|
||||
vendor
|
||||
composer.lock
|
|
@ -55,7 +55,7 @@ conventions):
|
|||
|
||||
<info>php app/console generate:bundle --namespace=Acme/BlogBundle</info>
|
||||
|
||||
Note that you can use <comment>/</comment> instead of <comment>\\</comment> for the namespace delimiter to avoid any
|
||||
Note that you can use <comment>/</comment> instead of <comment>\\ </comment>for the namespace delimiter to avoid any
|
||||
problem.
|
||||
|
||||
If you want to disable any user interaction, use <comment>--no-interaction</comment> but don't forget to pass all needed options:
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Command;
|
||||
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use Sensio\Bundle\GeneratorBundle\Command\GenerateBundleCommand;
|
||||
|
||||
class GenerateBundleCommandTest extends GenerateCommandTest
|
||||
{
|
||||
/**
|
||||
* @dataProvider getInteractiveCommandData
|
||||
*/
|
||||
public function testInteractiveCommand($options, $input, $expected)
|
||||
{
|
||||
list($namespace, $bundle, $dir, $format, $structure) = $expected;
|
||||
|
||||
$generator = $this->getGenerator();
|
||||
$generator
|
||||
->expects($this->once())
|
||||
->method('generate')
|
||||
->with($namespace, $bundle, $dir, $format, $structure)
|
||||
;
|
||||
|
||||
$tester = new CommandTester($this->getCommand($generator, $input));
|
||||
$tester->execute($options);
|
||||
}
|
||||
|
||||
public function getInteractiveCommandData()
|
||||
{
|
||||
$tmp = sys_get_temp_dir();
|
||||
|
||||
return array(
|
||||
array(array('--dir' => $tmp), "Foo/BarBundle\n", array('Foo\BarBundle', 'FooBarBundle', $tmp.'/', 'annotation', false)),
|
||||
array(array('--dir' => $tmp), "Foo/BarBundle\nBarBundle\nfoo\nyml\nn", array('Foo\BarBundle', 'BarBundle', 'foo/', 'yml', false)),
|
||||
array(array('--dir' => $tmp, '--format' => 'yml', '--bundle-name' => 'BarBundle', '--structure' => true), "Foo/BarBundle\n", array('Foo\BarBundle', 'BarBundle', $tmp.'/', 'yml', true)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getNonInteractiveCommandData
|
||||
*/
|
||||
public function testNonInteractiveCommand($options, $expected)
|
||||
{
|
||||
list($namespace, $bundle, $dir, $format, $structure) = $expected;
|
||||
|
||||
$generator = $this->getGenerator();
|
||||
$generator
|
||||
->expects($this->once())
|
||||
->method('generate')
|
||||
->with($namespace, $bundle, $dir, $format, $structure)
|
||||
;
|
||||
|
||||
$tester = new CommandTester($this->getCommand($generator, ''));
|
||||
$tester->execute($options, array('interactive' => false));
|
||||
}
|
||||
|
||||
public function getNonInteractiveCommandData()
|
||||
{
|
||||
$tmp = sys_get_temp_dir();
|
||||
|
||||
return array(
|
||||
array(array('--dir' => $tmp, '--namespace' => 'Foo/BarBundle'), array('Foo\BarBundle', 'FooBarBundle', $tmp.'/', 'annotation', false)),
|
||||
array(array('--dir' => $tmp, '--namespace' => 'Foo/BarBundle', '--format' => 'yml', '--bundle-name' => 'BarBundle', '--structure' => true), array('Foo\BarBundle', 'BarBundle', $tmp.'/', 'yml', true)),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getCommand($generator, $input)
|
||||
{
|
||||
$command = $this
|
||||
->getMockBuilder('Sensio\Bundle\GeneratorBundle\Command\GenerateBundleCommand')
|
||||
->setMethods(array('checkAutoloader', 'updateKernel', 'updateRouting'))
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$command->setContainer($this->getContainer());
|
||||
$command->setHelperSet($this->getHelperSet($input));
|
||||
$command->setGenerator($generator);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
protected function getGenerator()
|
||||
{
|
||||
// get a noop generator
|
||||
return $this
|
||||
->getMockBuilder('Sensio\Bundle\GeneratorBundle\Generator\BundleGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('generate'))
|
||||
->getMock()
|
||||
;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Command;
|
||||
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Symfony\Component\Console\Helper\FormatterHelper;
|
||||
use Sensio\Bundle\GeneratorBundle\Command\Helper\DialogHelper;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
|
||||
abstract class GenerateCommandTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function getHelperSet($input)
|
||||
{
|
||||
$dialog = new DialogHelper();
|
||||
$dialog->setInputStream($this->getInputStream($input));
|
||||
|
||||
return new HelperSet(array(new FormatterHelper(), $dialog));
|
||||
}
|
||||
|
||||
protected function getBundle()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$bundle
|
||||
->expects($this->any())
|
||||
->method('getPath')
|
||||
->will($this->returnValue(sys_get_temp_dir()))
|
||||
;
|
||||
|
||||
return $bundle;
|
||||
}
|
||||
|
||||
protected function getInputStream($input)
|
||||
{
|
||||
$stream = fopen('php://memory', 'r+', false);
|
||||
fputs($stream, $input.str_repeat("\n", 10));
|
||||
rewind($stream);
|
||||
|
||||
return $stream;
|
||||
}
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\KernelInterface');
|
||||
$kernel
|
||||
->expects($this->any())
|
||||
->method('getBundle')
|
||||
->will($this->returnValue($this->getBundle()))
|
||||
;
|
||||
|
||||
$filesystem = $this->getMock('Symfony\Component\Filesystem\Filesystem');
|
||||
$filesystem
|
||||
->expects($this->any())
|
||||
->method('isAbsolutePath')
|
||||
->will($this->returnValue(true))
|
||||
;
|
||||
|
||||
$container = new Container();
|
||||
$container->set('kernel', $kernel);
|
||||
$container->set('filesystem', $filesystem);
|
||||
|
||||
$container->setParameter('kernel.root_dir', sys_get_temp_dir());
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Command;
|
||||
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand;
|
||||
|
||||
class GenerateDoctrineCrudCommandTest extends GenerateCommandTest
|
||||
{
|
||||
/**
|
||||
* @dataProvider getInteractiveCommandData
|
||||
*/
|
||||
public function testInteractiveCommand($options, $input, $expected)
|
||||
{
|
||||
list($entity, $format, $prefix, $withWrite) = $expected;
|
||||
|
||||
$generator = $this->getGenerator();
|
||||
$generator
|
||||
->expects($this->once())
|
||||
->method('generate')
|
||||
->with($this->getBundle(), $entity, $this->getDoctrineMetadata(), $format, $prefix, $withWrite)
|
||||
;
|
||||
|
||||
$tester = new CommandTester($this->getCommand($generator, $input));
|
||||
$tester->execute($options);
|
||||
}
|
||||
|
||||
public function getInteractiveCommandData()
|
||||
{
|
||||
return array(
|
||||
array(array(), "AcmeBlogBundle:Blog/Post\n", array('Blog\\Post', 'annotation', 'blog_post', false)),
|
||||
array(array('--entity' => 'AcmeBlogBundle:Blog/Post'), '', array('Blog\\Post', 'annotation', 'blog_post', false)),
|
||||
array(array(), "AcmeBlogBundle:Blog/Post\ny\nyml\nfoobar\n", array('Blog\\Post', 'yml', 'foobar', true)),
|
||||
array(array(), "AcmeBlogBundle:Blog/Post\ny\nyml\n/foobar\n", array('Blog\\Post', 'yml', 'foobar', true)),
|
||||
array(array('--entity' => 'AcmeBlogBundle:Blog/Post', '--format' => 'yml', '--route-prefix' => 'foo', '--with-write' => true), '', array('Blog\\Post', 'yml', 'foo', true)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getNonInteractiveCommandData
|
||||
*/
|
||||
public function testNonInteractiveCommand($options, $expected)
|
||||
{
|
||||
list($entity, $format, $prefix, $withWrite) = $expected;
|
||||
|
||||
$generator = $this->getGenerator();
|
||||
$generator
|
||||
->expects($this->once())
|
||||
->method('generate')
|
||||
->with($this->getBundle(), $entity, $this->getDoctrineMetadata(), $format, $prefix, $withWrite)
|
||||
;
|
||||
|
||||
$tester = new CommandTester($this->getCommand($generator, ''));
|
||||
$tester->execute($options, array('interactive' => false));
|
||||
}
|
||||
|
||||
public function getNonInteractiveCommandData()
|
||||
{
|
||||
return array(
|
||||
array(array('--entity' => 'AcmeBlogBundle:Blog/Post'), array('Blog\\Post', 'annotation', 'blog_post', false)),
|
||||
array(array('--entity' => 'AcmeBlogBundle:Blog/Post', '--format' => 'yml', '--route-prefix' => 'foo', '--with-write' => true), array('Blog\\Post', 'yml', 'foo', true)),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getCommand($generator, $input)
|
||||
{
|
||||
$command = $this
|
||||
->getMockBuilder('Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand')
|
||||
->setMethods(array('getEntityMetadata'))
|
||||
->getMock()
|
||||
;
|
||||
|
||||
$command
|
||||
->expects($this->any())
|
||||
->method('getEntityMetadata')
|
||||
->will($this->returnValue(array($this->getDoctrineMetadata())))
|
||||
;
|
||||
|
||||
$command->setContainer($this->getContainer());
|
||||
$command->setHelperSet($this->getHelperSet($input));
|
||||
$command->setGenerator($generator);
|
||||
$command->setFormGenerator($this->getFormGenerator());
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
protected function getDoctrineMetadata()
|
||||
{
|
||||
return $this
|
||||
->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadataInfo')
|
||||
->disableOriginalConstructor()
|
||||
->getMock()
|
||||
;
|
||||
}
|
||||
|
||||
protected function getGenerator()
|
||||
{
|
||||
// get a noop generator
|
||||
return $this
|
||||
->getMockBuilder('Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('generate'))
|
||||
->getMock()
|
||||
;
|
||||
}
|
||||
|
||||
protected function getFormGenerator()
|
||||
{
|
||||
return $this
|
||||
->getMockBuilder('Sensio\Bundle\GeneratorBundle\Generator\DoctrineFormGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('generate'))
|
||||
->getMock()
|
||||
;
|
||||
}
|
||||
|
||||
protected function getContainer()
|
||||
{
|
||||
$container = parent::getContainer();
|
||||
|
||||
$registry = $this->getMock('Symfony\Bridge\Doctrine\RegistryInterface');
|
||||
$registry
|
||||
->expects($this->any())
|
||||
->method('getEntityNamespace')
|
||||
->will($this->returnValue('Foo\\FooBundle\\Entity'))
|
||||
;
|
||||
|
||||
$container->set('doctrine', $registry);
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Command;
|
||||
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
use Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineEntityCommand;
|
||||
|
||||
class GenerateDoctrineEntityCommandTest extends GenerateCommandTest
|
||||
{
|
||||
/**
|
||||
* @dataProvider getInteractiveCommandData
|
||||
*/
|
||||
public function testInteractiveCommand($options, $input, $expected)
|
||||
{
|
||||
list($entity, $format, $fields) = $expected;
|
||||
|
||||
$generator = $this->getGenerator();
|
||||
$generator
|
||||
->expects($this->once())
|
||||
->method('generate')
|
||||
->with($this->getBundle(), $entity, $format, $fields)
|
||||
;
|
||||
|
||||
$tester = new CommandTester($this->getCommand($generator, $input));
|
||||
$tester->execute($options);
|
||||
}
|
||||
|
||||
public function getInteractiveCommandData()
|
||||
{
|
||||
return array(
|
||||
array(array(), "AcmeBlogBundle:Blog/Post\n", array('Blog\\Post', 'annotation', array())),
|
||||
array(array('--entity' => 'AcmeBlogBundle:Blog/Post'), '', array('Blog\\Post', 'annotation', array())),
|
||||
array(array(), "AcmeBlogBundle:Blog/Post\nyml\n\n", array('Blog\\Post', 'yml', array())),
|
||||
array(array(), "AcmeBlogBundle:Blog/Post\nyml\ntitle\n\n255\ndescription\ntext\n\n", array('Blog\\Post', 'yml', array(
|
||||
array('fieldName' => 'title', 'type' => 'string', 'length' => 255),
|
||||
array('fieldName' => 'description', 'type' => 'text'),
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getNonInteractiveCommandData
|
||||
*/
|
||||
public function testNonInteractiveCommand($options, $expected)
|
||||
{
|
||||
list($entity, $format, $fields) = $expected;
|
||||
|
||||
$generator = $this->getGenerator();
|
||||
$generator
|
||||
->expects($this->once())
|
||||
->method('generate')
|
||||
->with($this->getBundle(), $entity, $format, $fields)
|
||||
;
|
||||
$generator
|
||||
->expects($this->any())
|
||||
->method('isReservedKeyword')
|
||||
->will($this->returnValue(false))
|
||||
;
|
||||
|
||||
$tester = new CommandTester($this->getCommand($generator, ''));
|
||||
$tester->execute($options, array('interactive' => false));
|
||||
}
|
||||
|
||||
public function getNonInteractiveCommandData()
|
||||
{
|
||||
return array(
|
||||
array(array('--entity' => 'AcmeBlogBundle:Blog/Post'), array('Blog\\Post', 'annotation', array())),
|
||||
array(array('--entity' => 'AcmeBlogBundle:Blog/Post', '--format' => 'yml', '--fields' => 'title:string(255) description:text'), array('Blog\\Post', 'yml', array(
|
||||
array('fieldName' => 'title', 'type' => 'string', 'length' => 255),
|
||||
array('fieldName' => 'description', 'type' => 'text', 'length' => ''),
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
||||
protected function getCommand($generator, $input)
|
||||
{
|
||||
$command = new GenerateDoctrineEntityCommand();
|
||||
$command->setContainer($this->getContainer());
|
||||
$command->setHelperSet($this->getHelperSet($input));
|
||||
$command->setGenerator($generator);
|
||||
|
||||
return $command;
|
||||
}
|
||||
|
||||
protected function getGenerator()
|
||||
{
|
||||
// get a noop generator
|
||||
return $this
|
||||
->getMockBuilder('Sensio\Bundle\GeneratorBundle\Generator\DoctrineEntityGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('generate', 'isReservedKeyword'))
|
||||
->getMock()
|
||||
;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Generator;
|
||||
|
||||
use Sensio\Bundle\GeneratorBundle\Generator\BundleGenerator;
|
||||
|
||||
class BundleGeneratorTest extends GeneratorTest
|
||||
{
|
||||
public function testGenerateYaml()
|
||||
{
|
||||
$generator = new BundleGenerator($this->filesystem, __DIR__.'/../../Resources/skeleton/bundle');
|
||||
$generator->generate('Foo\BarBundle', 'FooBarBundle', $this->tmpDir, 'yml', false);
|
||||
|
||||
$files = array(
|
||||
'FooBarBundle.php',
|
||||
'Controller/DefaultController.php',
|
||||
'Resources/views/Default/index.html.twig',
|
||||
'Resources/config/routing.yml',
|
||||
'Tests/Controller/DefaultControllerTest.php',
|
||||
'Resources/config/services.yml',
|
||||
'DependencyInjection/Configuration.php',
|
||||
'DependencyInjection/FooBarExtension.php',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertTrue(file_exists($this->tmpDir.'/Foo/BarBundle/'.$file), sprintf('%s has been generated', $file));
|
||||
}
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Foo/BarBundle/FooBarBundle.php');
|
||||
$this->assertContains('namespace Foo\\BarBundle', $content);
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Foo/BarBundle/Controller/DefaultController.php');
|
||||
$this->assertContains('public function indexAction', $content);
|
||||
$this->assertNotContains('@Route("/hello/{name}"', $content);
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Foo/BarBundle/Resources/views/Default/index.html.twig');
|
||||
$this->assertContains('Hello {{ name }}!', $content);
|
||||
}
|
||||
|
||||
public function testGenerateAnnotation()
|
||||
{
|
||||
$generator = new BundleGenerator($this->filesystem, __DIR__.'/../../Resources/skeleton/bundle');
|
||||
$generator->generate('Foo\BarBundle', 'FooBarBundle', $this->tmpDir, 'annotation', false);
|
||||
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/Foo/BarBundle/Resources/config/routing.yml'));
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/Foo/BarBundle/Resources/config/routing.xml'));
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Foo/BarBundle/Controller/DefaultController.php');
|
||||
$this->assertContains('@Route("/hello/{name}"', $content);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Generator;
|
||||
|
||||
use Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator;
|
||||
|
||||
class DoctrineCrudGeneratorTest extends GeneratorTest
|
||||
{
|
||||
public function testGenerateYamlFull()
|
||||
{
|
||||
$this->getGenerator()->generate($this->getBundle(), 'Post', $this->getMetadata(), 'yml', '/post', true);
|
||||
|
||||
$files = array(
|
||||
'Controller/PostController.php',
|
||||
'Tests/Controller/PostControllerTest.php',
|
||||
'Resources/config/routing/post.yml',
|
||||
'Resources/views/Post/index.html.twig',
|
||||
'Resources/views/Post/show.html.twig',
|
||||
'Resources/views/Post/new.html.twig',
|
||||
'Resources/views/Post/edit.html.twig',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertTrue(file_exists($this->tmpDir.'/'.$file), sprintf('%s has been generated', $file));
|
||||
}
|
||||
|
||||
$files = array(
|
||||
'Resources/config/routing/post.xml',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/'.$file), sprintf('%s has not been generated', $file));
|
||||
}
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Controller/PostController.php');
|
||||
$strings = array(
|
||||
'namespace Foo\BarBundle\Controller;',
|
||||
'public function indexAction',
|
||||
'public function showAction',
|
||||
'public function newAction',
|
||||
'public function editAction',
|
||||
);
|
||||
foreach ($strings as $string) {
|
||||
$this->assertContains($string, $content);
|
||||
}
|
||||
}
|
||||
|
||||
public function testGenerateXml()
|
||||
{
|
||||
$this->getGenerator()->generate($this->getBundle(), 'Post', $this->getMetadata(), 'xml', '/post', false);
|
||||
|
||||
$files = array(
|
||||
'Controller/PostController.php',
|
||||
'Tests/Controller/PostControllerTest.php',
|
||||
'Resources/config/routing/post.xml',
|
||||
'Resources/views/Post/index.html.twig',
|
||||
'Resources/views/Post/show.html.twig',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertTrue(file_exists($this->tmpDir.'/'.$file), sprintf('%s has been generated', $file));
|
||||
}
|
||||
|
||||
$files = array(
|
||||
'Resources/config/routing/post.yml',
|
||||
'Resources/views/Post/new.html.twig',
|
||||
'Resources/views/Post/edit.html.twig',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/'.$file), sprintf('%s has not been generated', $file));
|
||||
}
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Controller/PostController.php');
|
||||
$strings = array(
|
||||
'namespace Foo\BarBundle\Controller;',
|
||||
'public function indexAction',
|
||||
'public function showAction',
|
||||
);
|
||||
foreach ($strings as $string) {
|
||||
$this->assertContains($string, $content);
|
||||
}
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Controller/PostController.php');
|
||||
$strings = array(
|
||||
'public function newAction',
|
||||
'public function editAction',
|
||||
'@Route',
|
||||
);
|
||||
foreach ($strings as $string) {
|
||||
$this->assertNotContains($string, $content);
|
||||
}
|
||||
}
|
||||
|
||||
public function testGenerateAnnotationWrite()
|
||||
{
|
||||
$this->getGenerator()->generate($this->getBundle(), 'Post', $this->getMetadata(), 'annotation', '/post', true);
|
||||
|
||||
$files = array(
|
||||
'Controller/PostController.php',
|
||||
'Tests/Controller/PostControllerTest.php',
|
||||
'Resources/views/Post/index.html.twig',
|
||||
'Resources/views/Post/show.html.twig',
|
||||
'Resources/views/Post/new.html.twig',
|
||||
'Resources/views/Post/edit.html.twig',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertTrue(file_exists($this->tmpDir.'/'.$file), sprintf('%s has been generated', $file));
|
||||
}
|
||||
|
||||
$files = array(
|
||||
'Resources/config/routing/post.yml',
|
||||
'Resources/config/routing/post.xml',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/'.$file), sprintf('%s has not been generated', $file));
|
||||
}
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Controller/PostController.php');
|
||||
$strings = array(
|
||||
'namespace Foo\BarBundle\Controller;',
|
||||
'public function indexAction',
|
||||
'public function showAction',
|
||||
'public function newAction',
|
||||
'public function editAction',
|
||||
'@Route',
|
||||
);
|
||||
foreach ($strings as $string) {
|
||||
$this->assertContains($string, $content);
|
||||
}
|
||||
}
|
||||
|
||||
public function testGenerateAnnotation()
|
||||
{
|
||||
$this->getGenerator()->generate($this->getBundle(), 'Post', $this->getMetadata(), 'annotation', '/post', false);
|
||||
|
||||
$files = array(
|
||||
'Controller/PostController.php',
|
||||
'Tests/Controller/PostControllerTest.php',
|
||||
'Resources/views/Post/index.html.twig',
|
||||
'Resources/views/Post/show.html.twig',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertTrue(file_exists($this->tmpDir.'/'.$file), sprintf('%s has been generated', $file));
|
||||
}
|
||||
|
||||
$files = array(
|
||||
'Resources/config/routing/post.yml',
|
||||
'Resources/config/routing/post.xml',
|
||||
'Resources/views/Post/new.html.twig',
|
||||
'Resources/views/Post/edit.html.twig',
|
||||
);
|
||||
foreach ($files as $file) {
|
||||
$this->assertFalse(file_exists($this->tmpDir.'/'.$file), sprintf('%s has not been generated', $file));
|
||||
}
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Controller/PostController.php');
|
||||
$strings = array(
|
||||
'namespace Foo\BarBundle\Controller;',
|
||||
'public function indexAction',
|
||||
'public function showAction',
|
||||
'@Route',
|
||||
);
|
||||
foreach ($strings as $string) {
|
||||
$this->assertContains($string, $content);
|
||||
}
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Controller/PostController.php');
|
||||
$strings = array(
|
||||
'public function newAction',
|
||||
'public function editAction',
|
||||
);
|
||||
foreach ($strings as $string) {
|
||||
$this->assertNotContains($string, $content);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getGenerator()
|
||||
{
|
||||
return new DoctrineCrudGenerator($this->filesystem, __DIR__.'/../../Resources/skeleton/crud');
|
||||
}
|
||||
|
||||
protected function getBundle()
|
||||
{
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$bundle->expects($this->any())->method('getPath')->will($this->returnValue($this->tmpDir));
|
||||
$bundle->expects($this->any())->method('getName')->will($this->returnValue('FooBarBundle'));
|
||||
$bundle->expects($this->any())->method('getNamespace')->will($this->returnValue('Foo\BarBundle'));
|
||||
|
||||
return $bundle;
|
||||
}
|
||||
|
||||
public function getMetadata()
|
||||
{
|
||||
$metadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadataInfo')->disableOriginalConstructor()->getMock();
|
||||
$metadata->identifier = array('id');
|
||||
$metadata->fieldMappings = array('title' => array('type' => 'string'));
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Generator;
|
||||
|
||||
use Sensio\Bundle\GeneratorBundle\Generator\DoctrineFormGenerator;
|
||||
|
||||
class DoctrineFormGeneratorTest extends GeneratorTest
|
||||
{
|
||||
public function testGenerate()
|
||||
{
|
||||
$generator = new DoctrineFormGenerator($this->filesystem, __DIR__.'/../../Resources/skeleton/form');
|
||||
|
||||
$bundle = $this->getMock('Symfony\Component\HttpKernel\Bundle\BundleInterface');
|
||||
$bundle->expects($this->any())->method('getPath')->will($this->returnValue($this->tmpDir));
|
||||
$bundle->expects($this->any())->method('getNamespace')->will($this->returnValue('Foo\BarBundle'));
|
||||
|
||||
$metadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadataInfo')->disableOriginalConstructor()->getMock();
|
||||
$metadata->identifier = array('id');
|
||||
$metadata->associationMappings = array('title' => array('type' => 'string'));
|
||||
|
||||
$generator->generate($bundle, 'Post', $metadata);
|
||||
|
||||
$this->assertTrue(file_exists($this->tmpDir.'/Form/PostType.php'));
|
||||
|
||||
$content = file_get_contents($this->tmpDir.'/Form/PostType.php');
|
||||
$this->assertContains('->add(\'title\')', $content);
|
||||
$this->assertContains('class PostType extends AbstractType', $content);
|
||||
$this->assertContains("'data_class' => 'Foo\BarBundle\Entity\Post'", $content);
|
||||
$this->assertContains("'foo_barbundle_posttype'", $content);
|
||||
}
|
||||
}
|
32
vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle/Tests/Generator/GeneratorTest.php
vendored
Normal file
32
vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle/Tests/Generator/GeneratorTest.php
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\GeneratorBundle\Tests\Generator;
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
abstract class GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $filesystem;
|
||||
protected $tmpDir;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->tmpDir = sys_get_temp_dir().'/sf2';
|
||||
$this->filesystem = new Filesystem();
|
||||
$this->filesystem->remove($this->tmpDir);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
$this->filesystem->remove($this->tmpDir);
|
||||
}
|
||||
}
|
20
vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle/phpunit.xml.dist
vendored
Normal file
20
vendor/sensio/generator-bundle/Sensio/Bundle/GeneratorBundle/phpunit.xml.dist
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="./vendor/autoload.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="SensioGeneratorBundle">
|
||||
<directory suffix="Test.php">./Tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory>./</directory>
|
||||
<exclude>
|
||||
<directory>./Resources</directory>
|
||||
<directory>./Tests</directory>
|
||||
<directory>./vendor</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
|
@ -0,0 +1,6 @@
|
|||
.DS_Store
|
||||
tests/acceptance.conf.php
|
||||
tests/smoke.conf.php
|
||||
build/*
|
||||
.project
|
||||
.settings/*
|
|
@ -0,0 +1,100 @@
|
|||
Changelog since Version 4.x.x
|
||||
=============================
|
||||
|
||||
4.2.2 (2012-XX-XX)
|
||||
------------------
|
||||
|
||||
* n/a
|
||||
|
||||
4.2.1 (2012-07-13)
|
||||
------------------
|
||||
|
||||
* changed the coding standards to PSR-1/2
|
||||
* fixed issue with autoloading
|
||||
* added NativeQpContentEncoder to enhance performance (for PHP 5.3+)
|
||||
|
||||
4.2.0 (2012-06-29)
|
||||
------------------
|
||||
|
||||
* added documentation about how to use the Japanese support introduced in 4.1.8
|
||||
* added a way to override the default configuration in a lazy way
|
||||
* changed the PEAR init script to lazy-load the initialization
|
||||
* fixed a bug when calling Swift_Preferences before anything else (regression introduced in 4.1.8)
|
||||
|
||||
4.1.8 (2012-06-17)
|
||||
------------------
|
||||
|
||||
* added Japanese iso-2022-jp support
|
||||
* changed the init script to lazy-load the initialization
|
||||
* fixed docblocks (@id) which caused some problems with libraries parsing the dobclocks
|
||||
* fixed Swift_Mime_Headers_IdentificationHeader::setId() when passed an array of ids
|
||||
* fixed encoding of email addresses in headers
|
||||
* added replacements setter to the Decorator plugin
|
||||
|
||||
4.1.7 (2012-04-26)
|
||||
------------------
|
||||
|
||||
* fixed QpEncoder safeMapShareId property
|
||||
|
||||
4.1.6 (2012-03-23)
|
||||
------------------
|
||||
|
||||
* reduced the size of serialized Messages
|
||||
|
||||
4.1.5 (2012-01-04)
|
||||
------------------
|
||||
|
||||
* enforced Swift_Spool::queueMessage() to return a Boolean
|
||||
* made an optimization to the memory spool: start the transport only when required
|
||||
* prevented stream_socket_client() from generating an error and throw a Swift_TransportException instead
|
||||
* fixed a PHP warning when calling to mail() when safe_mode is off
|
||||
* many doc tweaks
|
||||
|
||||
4.1.4 (2011-12-16)
|
||||
------------------
|
||||
|
||||
* added a memory spool (Swift_MemorySpool)
|
||||
* fixed too many opened files when sending emails with attachments
|
||||
|
||||
4.1.3 (2011-10-27)
|
||||
------------------
|
||||
|
||||
* added STARTTLS support
|
||||
* added missing @return tags on fluent methods
|
||||
* added a MessageLogger plugin that logs all sent messages
|
||||
* added composer.json
|
||||
|
||||
4.1.2 (2011-09-13)
|
||||
------------------
|
||||
|
||||
* fixed wrong detection of magic_quotes_runtime
|
||||
* fixed fatal errors when no To or Subject header has been set
|
||||
* fixed charset on parameter header continuations
|
||||
* added documentation about how to install Swiftmailer from the PEAR channel
|
||||
* fixed various typos and markup problem in the documentation
|
||||
* fixed warning when cache directory does not exist
|
||||
* fixed "slashes are escaped" bug
|
||||
* changed require_once() to require() in autoload
|
||||
|
||||
4.1.1 (2011-07-04)
|
||||
------------------
|
||||
|
||||
* added missing file in PEAR package
|
||||
|
||||
4.1.0 (2011-06-30)
|
||||
------------------
|
||||
|
||||
* documentation has been converted to ReST
|
||||
|
||||
4.1.0 RC1 (2011-06-17)
|
||||
----------------------
|
||||
|
||||
New features:
|
||||
|
||||
* changed the Decorator Plugin to allow replacements in all headers
|
||||
* added Swift_Mime_Grammar and Swift_Validate to validate an email address
|
||||
* modified the autoloader to lazy-initialize Swiftmailer
|
||||
* removed Swift_Mailer::batchSend()
|
||||
* added NullTransport
|
||||
* added new plugins: RedirectingPlugin and ImpersonatePlugin
|
||||
* added a way to send messages asynchronously (Spool)
|
|
@ -0,0 +1,16 @@
|
|||
Swift Mailer
|
||||
------------
|
||||
|
||||
Swift Mailer is a component based mailing solution for PHP 5.
|
||||
It is released under the LGPL license.
|
||||
|
||||
Homepage: http://swiftmailer.org
|
||||
Documentation: http://swiftmailer.org/docs
|
||||
Mailing List: http://groups.google.com/group/swiftmailer
|
||||
Bugs: https://github.com/swiftmailer/swiftmailer/issues
|
||||
Repository: https://github.com/swiftmailer/swiftmailer
|
||||
|
||||
Swift Mailer is highly object-oriented by design and lends itself
|
||||
to use in complex web application with a great deal of flexibility.
|
||||
|
||||
For full details on usage, see the documentation.
|
|
@ -0,0 +1,67 @@
|
|||
This README applies to anyone who checks out the source from git.
|
||||
|
||||
If you're reading this page on github.com, and you don't have git
|
||||
installed or know about git, you can download this repository by
|
||||
using the "download" button on github.com, right above the file
|
||||
list.
|
||||
|
||||
PREAMBLE:
|
||||
---------
|
||||
|
||||
The git repository is structured in the expected way where "master" is the
|
||||
main branch you should use if you want to have bleeding-edge updates. Any
|
||||
other branch should be ignored since it will likely contain unstable
|
||||
and/or experimental developments.
|
||||
|
||||
Generally speaking you should feel safe using the "master" branch in
|
||||
production code. Anything likely to break will be committed to another
|
||||
branch. Only bugfixes and clean non-breaking feature additions will be
|
||||
performed in master.
|
||||
|
||||
All releases (post version 4.0.0) are tagged using the version number of
|
||||
that release. Earlier versions exist in a subversion repository at the
|
||||
old sourceforge project page.
|
||||
|
||||
|
||||
WHAT IS SWIFT MAILER?
|
||||
---------------------
|
||||
|
||||
Swift Mailer is a component based mailing solution for PHP 5.
|
||||
It is released under the LGPL license.
|
||||
|
||||
Homepage: http://swiftmailer.org/
|
||||
Documentation: http://swiftmailer.org/docs
|
||||
Mailing List: http://groups.google.com/group/swiftmailer
|
||||
Bugs: https://github.com/swiftmailer/swiftmailer/issues
|
||||
Repository: https://github.com/swiftmailer/swiftmailer
|
||||
|
||||
Swift Mailer is highly object-oriented by design and lends itself
|
||||
to use in complex web application with a great deal of flexibility.
|
||||
|
||||
For full details on usage, see the documentation.
|
||||
|
||||
|
||||
WHY SO MUCH CLUTTER?
|
||||
--------------------
|
||||
As you can probably see, there are a lot more files in here than you find in
|
||||
the pre-packaged versions. That's because I store notes (UML, RFCs etc) in
|
||||
the repository.
|
||||
|
||||
The main library files live in /lib and the tests live in /tests. You can run
|
||||
the tests by pointing your web browser at /test-suite, or by running the
|
||||
command "php test-suite/run.php". Some tests will be "skipped" if
|
||||
tests/smoke.conf.php and tests/acceptance.conf.php are not editted. This is
|
||||
harmless and normal.
|
||||
|
||||
If you want to create a bundled-up package from subversion you can do so if
|
||||
you have Ant (http://ant.apache.org/) installed. Simply run "ant package"
|
||||
from this directory and the tar.gz file will be created in the /build
|
||||
directory.
|
||||
|
||||
Running the command "ant" with no arguments will bundle up the package without
|
||||
compressing it into a tar.gz file.
|
||||
|
||||
Tests can also be run using "ant test" provided php is on your PATH
|
||||
environment variable.
|
||||
|
||||
EoM
|
|
@ -1 +1 @@
|
|||
Swift-4.2.1
|
||||
Swift-4.2.2-DEV
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
<!-- Ant build file for Swift Mailer (Standard Edition) -->
|
||||
<project name="Swift Mailer SE" default="bundle">
|
||||
|
||||
<!-- Config settings -->
|
||||
<property name="path" value="." />
|
||||
<property name="builddir" value="${path}/build" />
|
||||
<property name="src.versionfile" value="${path}/VERSION" />
|
||||
<!-- Generate version info from VERSION file -->
|
||||
<loadfile property="bundle.name" srcFile="${src.versionfile}">
|
||||
<filterchain>
|
||||
<striplinebreaks />
|
||||
</filterchain>
|
||||
</loadfile>
|
||||
<!-- Generate version number -->
|
||||
<loadfile property="bundle.version" srcFile="${src.versionfile}">
|
||||
<filterchain>
|
||||
<striplinebreaks />
|
||||
<tokenfilter>
|
||||
<replacestring from="Swift-" to=""/>
|
||||
</tokenfilter>
|
||||
</filterchain>
|
||||
</loadfile>
|
||||
<property name="src.readmefile" value="${path}/README" />
|
||||
<property name="src.changesfile" value="${path}/CHANGES" />
|
||||
<property name="src.libdir" value="${path}/lib" />
|
||||
<property name="src.testsuite" value="${path}/test-suite" />
|
||||
<property name="src.tests" value="${path}/tests" />
|
||||
<property name="builddir.package" value="${builddir}/${bundle.name}" />
|
||||
<property name="runtests" value="" />
|
||||
<filelist id="src.licenses" dir="${path}">
|
||||
<file name="LICENSE" />
|
||||
</filelist>
|
||||
<fileset id="build.simpletest.unneeded"
|
||||
dir="${builddir.package}/test-suite/lib/simpletest">
|
||||
<include name="docs/" />
|
||||
<include name="tutorials/" />
|
||||
<include name="extensions/" />
|
||||
<include name="test/" />
|
||||
<include name="packages/" />
|
||||
</fileset>
|
||||
|
||||
|
||||
<!-- Bundle all files into a central location -->
|
||||
<target name="bundle" depends="prepare, clean, copy-classes">
|
||||
<copy file="${src.versionfile}" todir="${builddir.package}" />
|
||||
<copy file="${src.changesfile}" todir="${builddir.package}" />
|
||||
<copy todir="${builddir.package}">
|
||||
<filelist refid="src.licenses" />
|
||||
</copy>
|
||||
<copy file="${src.readmefile}" todir="${builddir.package}" />
|
||||
<move file="${builddir.package}/tests/acceptance.conf.php.default"
|
||||
tofile="${builddir.package}/tests/acceptance.conf.php" />
|
||||
<move file="${builddir.package}/tests/smoke.conf.php.default"
|
||||
tofile="${builddir.package}/tests/smoke.conf.php" />
|
||||
</target>
|
||||
|
||||
<!-- Copy some *.default files to their required files if needed -->
|
||||
<target name="prepare">
|
||||
<copy file="${src.tests}/acceptance.conf.php.default"
|
||||
tofile="${src.tests}/acceptance.conf.php" />
|
||||
<copy file="${src.tests}/smoke.conf.php.default"
|
||||
tofile="${src.tests}/smoke.conf.php" />
|
||||
</target>
|
||||
|
||||
<!-- Clean out the build directory -->
|
||||
<target name="clean">
|
||||
<delete includeemptydirs="true">
|
||||
<fileset dir="${builddir}" includes="**/*" />
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<!-- Copy all classes from the class path to the bundle -->
|
||||
<target name="copy-classes">
|
||||
<copy todir="${builddir.package}/lib">
|
||||
<fileset dir="${src.libdir}" />
|
||||
<filterchain>
|
||||
<replacetokens>
|
||||
<token key="SWIFT_VERSION_NUMBER" value="${bundle.version}"/>
|
||||
</replacetokens>
|
||||
</filterchain>
|
||||
</copy>
|
||||
<copy todir="${builddir.package}/test-suite">
|
||||
<fileset dir="${src.testsuite}" />
|
||||
</copy>
|
||||
<copy todir="${builddir.package}/tests">
|
||||
<fileset dir="${src.tests}" />
|
||||
</copy>
|
||||
<delete includeemptydirs="true">
|
||||
<fileset refid="build.simpletest.unneeded" />
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<!-- Package up the project as a gzip file -->
|
||||
<target name="package" depends="bundle">
|
||||
<tar destfile="${builddir.package}.tar.gz" compression="gzip" longfile="gnu">
|
||||
<fileset dir="${builddir}" />
|
||||
</tar>
|
||||
<delete includeemptydirs="true">
|
||||
<fileset dir="${builddir.package}" includes="**" />
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<!-- Run the included unit tests -->
|
||||
<target name="test" depends="prepare, clean, copy-classes">
|
||||
<exec executable="php" failonerror="true">
|
||||
<env key="_" value="php" />
|
||||
<arg value="${builddir.package}/test-suite/run.php" />
|
||||
<arg value="${runtests}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
if (!isset($argv[1]))
|
||||
{
|
||||
die('You must provide the version (1.0.0)');
|
||||
}
|
||||
|
||||
if (!isset($argv[2]))
|
||||
{
|
||||
die('You must provide the stability (alpha, beta, or stable)');
|
||||
}
|
||||
|
||||
$context = array(
|
||||
'date' => date('Y-m-d'),
|
||||
'time' => date('H:m:00'),
|
||||
'version' => $argv[1],
|
||||
'api_version' => $argv[1],
|
||||
'stability' => $argv[2],
|
||||
'api_stability' => $argv[2],
|
||||
);
|
||||
|
||||
$context['files'] = '';
|
||||
$path = realpath(dirname(__FILE__).'/lib/classes/Swift');
|
||||
foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::LEAVES_ONLY) as $file)
|
||||
{
|
||||
if (preg_match('/\.php$/', $file))
|
||||
{
|
||||
$name = str_replace($path.'/', '', $file);
|
||||
$context['files'] .= ' <file install-as="Swift/'.$name.'" name="'.$name.'" role="php" />'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
$template = file_get_contents(dirname(__FILE__).'/package.xml.tpl');
|
||||
$content = preg_replace_callback('/\{\{\s*([a-zA-Z0-9_]+)\s*\}\}/', 'replace_parameters', $template);
|
||||
file_put_contents(dirname(__FILE__).'/package.xml', $content);
|
||||
|
||||
function replace_parameters($matches)
|
||||
{
|
||||
global $context;
|
||||
|
||||
return isset($context[$matches[1]]) ? $context[$matches[1]] : null;
|
||||
}
|
|
@ -20,7 +20,7 @@ class Swift_SmtpTransport extends Swift_Transport_EsmtpTransport
|
|||
* Create a new SmtpTransport, optionally with $host, $port and $security.
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param int $security
|
||||
* @param string $security
|
||||
*/
|
||||
public function __construct($host = 'localhost', $port = 25, $security = null)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ class Swift_SmtpTransport extends Swift_Transport_EsmtpTransport
|
|||
* Create a new SmtpTransport instance.
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param int $security
|
||||
* @param string $security
|
||||
* @return Swift_SmtpTransport
|
||||
*/
|
||||
public static function newInstance($host = 'localhost', $port = 25, $security = null)
|
||||
|
|
|
@ -21,9 +21,11 @@ define('SWIFT_REQUIRED_LOADED', true);
|
|||
//Load Swift utility class
|
||||
require dirname(__FILE__) . '/classes/Swift.php';
|
||||
|
||||
function _swiftmailer_init()
|
||||
{
|
||||
require dirname(__FILE__) . '/swift_init.php';
|
||||
if (!function_exists('_swiftmailer_init')) {
|
||||
function _swiftmailer_init()
|
||||
{
|
||||
require dirname(__FILE__) . '/swift_init.php';
|
||||
}
|
||||
}
|
||||
|
||||
//Start the autoloader and lazy-load the init script to set up dependency injection
|
||||
|
|
|
@ -21,9 +21,11 @@ define('SWIFT_REQUIRED_LOADED', true);
|
|||
//Load Swift utility class
|
||||
require dirname(__FILE__) . '/Swift.php';
|
||||
|
||||
function _swiftmailer_init()
|
||||
{
|
||||
require dirname(__FILE__) . '/swift_init.php';
|
||||
if (!function_exists('_swiftmailer_init')) {
|
||||
function _swiftmailer_init()
|
||||
{
|
||||
require dirname(__FILE__) . '/swift_init.php';
|
||||
}
|
||||
}
|
||||
|
||||
//Start the autoloader and lazy-load the init script to set up dependency injection
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
Applications I need to test with
|
||||
---------------------------------
|
||||
|
||||
Standalone (can read .eml files):
|
||||
---------------------------------
|
||||
Microsoft Entourage (can assume same as outlook)
|
||||
Mozilla Thunderbird
|
||||
Apple Mail
|
||||
|
||||
Web-based:
|
||||
----------
|
||||
Hotmail
|
||||
Gmail
|
||||
Yahoo!
|
||||
Mail2Web
|
|
@ -0,0 +1,46 @@
|
|||
Following is a list of character sets along with their widths:
|
||||
--------------------------------------------------------------
|
||||
|
||||
1 Octet 8bit:
|
||||
-------------
|
||||
Windows 125* (CP125*)
|
||||
CP*
|
||||
ANSI
|
||||
ISO-8859-* (IEC-8859-*)
|
||||
Macintosh (Mac OS Roman)
|
||||
KOI8-U (potentially KOI*8-*)
|
||||
KOI8-R
|
||||
MIK
|
||||
Cork (T1)
|
||||
ISCII
|
||||
VISCII
|
||||
|
||||
|
||||
1 Octet 7bit:
|
||||
-------------
|
||||
US-ASCII
|
||||
K0I7
|
||||
|
||||
2 octets 16 bit:
|
||||
----------------
|
||||
UCS-2
|
||||
UTF-16* (UTF-16BE etc)
|
||||
|
||||
4-octets 32 bit:
|
||||
----------------
|
||||
UCS-4
|
||||
UTF-32
|
||||
|
||||
Variable-width:
|
||||
----------------------------
|
||||
Big5 - http://en.wikipedia.org/wiki/Big5 (1-2 bytes: 00-7f=1, 81-fe=2)
|
||||
HKSCS - http://en.wikipedia.org/wiki/HKSCS (a big5 variant, but some variants use 10646)
|
||||
ISO-10646 (IEC-10646) - http://en.wikipedia.org/wiki/ISO_10646 (unicode)
|
||||
UTF-8 (1-5 bytes)
|
||||
ISO-2022 (IEC-2022) - http://en.wikipedia.org/wiki/ISO_2022
|
||||
Shift-JIS - http://en.wikipedia.org/wiki/Shift-JIS
|
||||
|
||||
A good resource:
|
||||
----------------
|
||||
http://en.wikipedia.org/wiki/Character_encoding#Simple_character_sets
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<message>
|
||||
<subject>Some test message</subject>
|
||||
<to name="Chris Corbyn">chris@w3style.co.uk</to>
|
||||
<to name="Mark Corbyn">mark@swiftmailer.org</to>
|
||||
<from>chris.corbyn@sitepoint.com</from>
|
||||
<content-type>text/plain</content-type>
|
||||
<body>
|
||||
Here's a recipe for beef stifado
|
||||
</body>
|
||||
<part>
|
||||
<content-type>text/html</content-type>
|
||||
<body>
|
||||
This is the other part
|
||||
</body>
|
||||
</part>
|
||||
<attachment>
|
||||
<content-type>application/pdf</content-type>
|
||||
<filename>stifado.pdf</filename>
|
||||
<body type="file">/path/to/stifado.pdf</body>
|
||||
</attachment>
|
||||
</message>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,395 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group N. Freed
|
||||
Request For Comments: 1854 Innosoft International, Inc.
|
||||
Category: Standards Track A. Cargille, WG Chair
|
||||
October 1995
|
||||
|
||||
|
||||
SMTP Service Extension
|
||||
for Command Pipelining
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Abstract
|
||||
|
||||
This memo defines an extension to the SMTP service whereby a server
|
||||
can indicate the extent of its ability to accept multiple commands in
|
||||
a single TCP send operation. Using a single TCP send operation for
|
||||
multiple commands can improve SMTP performance significantly.
|
||||
|
||||
Introduction
|
||||
|
||||
Although SMTP is widely and robustly deployed, certain extensions may
|
||||
nevertheless prove useful. In particular, many parts of the Internet
|
||||
make use of high latency network links.
|
||||
|
||||
SMTP's intrinsic one command-one response structure is significantly
|
||||
penalized by high latency links, often to the point where the factors
|
||||
contributing to overall connection time are dominated by the time
|
||||
spent waiting for responses to individual commands (turnaround time).
|
||||
|
||||
In the best of all worlds it would be possible to simply deploy SMTP
|
||||
client software that makes use of command pipelining: batching up
|
||||
multiple commands into single TCP send operations. Unfortunately, the
|
||||
original SMTP specification [1] did not explicitly state that SMTP
|
||||
servers must support this. As a result a non-trivial number of
|
||||
Internet SMTP servers cannot adequately handle command pipelining.
|
||||
Flaws known to exist in deployed servers include:
|
||||
|
||||
(1) Connection handoff and buffer flushes in the middle of
|
||||
the SMTP dialogue. Creation of server processes for
|
||||
incoming SMTP connections is a useful, obvious, and
|
||||
harmless implementation technique. However, some SMTP
|
||||
servers defer process forking and connection handoff
|
||||
|
||||
|
||||
|
||||
Freed & Cargille Standards Track [Page 1]
|
||||
|
||||
RFC 1854 SMTP Pipelining October 1995
|
||||
|
||||
|
||||
until some intermediate point in the SMTP dialogue.
|
||||
When this is done material read from the TCP connection
|
||||
and kept in process buffers can be lost.
|
||||
|
||||
(2) Flushing the TCP input buffer when an SMTP command
|
||||
fails. SMTP commands often fail but there is no reason
|
||||
to flush the TCP input buffer when this happens.
|
||||
Nevertheless, some SMTP servers do this.
|
||||
|
||||
(3) Improper processing and promulgation of SMTP command
|
||||
failures. For example, some SMTP servers will refuse to
|
||||
accept a DATA command if the last RCPT TO command
|
||||
fails, paying no attention to the success or failure of
|
||||
prior RCPT TO command results. Other servers will
|
||||
accept a DATA command even when all previous RCPT TO
|
||||
commands have failed. Although it is possible to
|
||||
accommodate this sort of behavior in a client that
|
||||
employs command pipelining, it does complicate the
|
||||
construction of the client unnecessarily.
|
||||
|
||||
This memo uses the mechanism described in [2] to define an extension
|
||||
to the SMTP service whereby an SMTP server can declare that it is
|
||||
capable of handling pipelined commands. The SMTP client can then
|
||||
check for this declaration and use pipelining only when the server
|
||||
declares itself capable of handling it.
|
||||
|
||||
1. Framework for the Command Pipelining Extension
|
||||
|
||||
The Command Pipelining extension is defined as follows:
|
||||
|
||||
(1) the name of the SMTP service extension is Pipelining;
|
||||
|
||||
(2) the EHLO keyword value associated with the extension is
|
||||
PIPELINING;
|
||||
|
||||
(3) no parameter is used with the PIPELINING EHLO keyword;
|
||||
|
||||
(4) no additional parameters are added to either the MAIL
|
||||
FROM or RCPT TO commands.
|
||||
|
||||
(5) no additional SMTP verbs are defined by this extension;
|
||||
and,
|
||||
|
||||
(6) the next section specifies how support for the
|
||||
extension affects the behavior of a server and client
|
||||
SMTP.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Cargille Standards Track [Page 2]
|
||||
|
||||
RFC 1854 SMTP Pipelining October 1995
|
||||
|
||||
|
||||
2. The Pipelining Service Extension
|
||||
|
||||
When a client SMTP wishes to employ command pipelining, it first
|
||||
issues the EHLO command to the server SMTP. If the server SMTP
|
||||
responds with code 250 to the EHLO command, and the response includes
|
||||
the EHLO keyword value PIPELINING, then the server SMTP has indicated
|
||||
that it can accommodate SMTP command pipelining.
|
||||
|
||||
2.1. Client use of pipelining
|
||||
|
||||
Once the client SMTP has confirmed that support exists for the
|
||||
pipelining extension, the client SMTP may then elect to transmit
|
||||
groups of SMTP commands in batches without waiting for a response to
|
||||
each individual command. In particular, the commands RSET, MAIL FROM,
|
||||
SEND FROM, SOML FROM, SAML FROM, and RCPT TO can all appear anywhere
|
||||
in a pipelined command group. The EHLO, DATA, VRFY, EXPN, TURN,
|
||||
QUIT, and NOOP commands can only appear as the last command in a
|
||||
group since their success or failure produces a change of state which
|
||||
the client SMTP must accommodate. (NOOP is included in this group so
|
||||
it can be used as a synchronization point.)
|
||||
|
||||
Additional commands added by other SMTP extensions may only appear as
|
||||
the last command in a group unless otherwise specified by the
|
||||
extensions that define the commands.
|
||||
|
||||
The actual transfer of message content is explicitly allowed to be
|
||||
the first "command" in a group. That is, the RSET/MAIL FROM sequence
|
||||
necessary to initiate a new message transaction can be placed in the
|
||||
same group as the final transfer of the headers and body of the
|
||||
previous message.
|
||||
|
||||
Client SMTP implementations that employ pipelining MUST check ALL
|
||||
statuses associated with each command in a group. For example, if
|
||||
none of the RCPT TO recipient addresses were accepted the client must
|
||||
then check the response to the DATA command -- the client cannot
|
||||
assume that the DATA command will be rejected just because none of
|
||||
the RCPT TO commands worked. If the DATA command was properly
|
||||
rejected the client SMTP can just issue RSET, but if the DATA command
|
||||
was accepted the client SMTP should send a single dot.
|
||||
|
||||
Command statuses MUST be coordinated with responses by counting each
|
||||
separate response and correlating that count with the number of
|
||||
commands known to have been issued. Multiline responses MUST be
|
||||
supported. Matching on the basis of either the error code value or
|
||||
associated text is expressly forbidden.
|
||||
|
||||
Client SMTP implementations MAY elect to operate in a nonblocking
|
||||
fashion, processing server responses immediately upon receipt, even
|
||||
|
||||
|
||||
|
||||
Freed & Cargille Standards Track [Page 3]
|
||||
|
||||
RFC 1854 SMTP Pipelining October 1995
|
||||
|
||||
|
||||
if there is still data pending transmission from the client's
|
||||
previous TCP send operation. If nonblocking operation is not
|
||||
supported, however, client SMTP implementations MUST also check the
|
||||
TCP window size and make sure that each group of commands fits
|
||||
entirely within the window. The window size is usually, but not
|
||||
always, 4K octets. Failure to perform this check can lead to
|
||||
deadlock conditions.
|
||||
|
||||
Clients MUST NOT confuse responses to multiple commands with
|
||||
multiline responses. Each command requires one or more lines of
|
||||
response, the last line not containing a dash between the response
|
||||
code and the response string.
|
||||
|
||||
2.2. Server support of pipelining
|
||||
|
||||
A server SMTP implementation that offers the pipelining extension:
|
||||
|
||||
(1) MUST NOT flush or otherwise lose the contents of the
|
||||
TCP input buffer under any circumstances whatsoever.
|
||||
|
||||
(2) SHOULD issue a positive response to the DATA command if
|
||||
and only if one or more valid RCPT TO addresses have
|
||||
been previously received.
|
||||
|
||||
(3) MUST NOT, after issuing a positive response to a DATA
|
||||
command with no valid recipients and subsequently
|
||||
receiving an empty message, send any message whatsoever
|
||||
to anybody.
|
||||
|
||||
(4) SHOULD elect to store responses to grouped RSET, MAIL
|
||||
FROM, SEND FROM, SOML FROM, SAML FROM, and RCPT TO
|
||||
commands in an internal buffer so they can sent as a
|
||||
unit.
|
||||
|
||||
(5) MUST NOT buffer responses to EHLO, DATA, VRFY, EXPN,
|
||||
TURN, QUIT, and NOOP.
|
||||
|
||||
(6) MUST NOT buffer responses to unrecognized commands.
|
||||
|
||||
(7) MUST send all pending responses immediately whenever
|
||||
the local TCP input buffer is emptied.
|
||||
|
||||
(8) MUST NOT make assumptions about commands that are yet
|
||||
to be received.
|
||||
|
||||
(9) SHOULD issue response text that indicates, either
|
||||
implicitly or explicitly, what command the response
|
||||
matches.
|
||||
|
||||
|
||||
|
||||
Freed & Cargille Standards Track [Page 4]
|
||||
|
||||
RFC 1854 SMTP Pipelining October 1995
|
||||
|
||||
|
||||
The overriding intent of these server requirements is to make it as
|
||||
easy as possible for servers to conform to these pipelining
|
||||
extensions.
|
||||
|
||||
3. Examples
|
||||
|
||||
Consider the following SMTP dialogue that does not use pipelining:
|
||||
|
||||
S: <wait for open connection>
|
||||
C: <open connection to server>
|
||||
S: 220 innosoft.com SMTP service ready
|
||||
C: HELO dbc.mtview.ca.us
|
||||
S: 250 innosoft.com
|
||||
C: MAIL FROM:<mrose@dbc.mtview.ca.us>
|
||||
S: 250 sender <mrose@dbc.mtview.ca.us> OK
|
||||
C: RCPT TO:<ned@innosoft.com>
|
||||
S: 250 recipient <ned@innosoft.com> OK
|
||||
C: RCPT TO:<dan@innosoft.com>
|
||||
S: 250 recipient <dan@innosoft.com> OK
|
||||
C: RCPT TO:<kvc@innosoft.com>
|
||||
S: 250 recipient <kvc@innosoft.com> OK
|
||||
C: DATA
|
||||
S: 354 enter mail, end with line containing only "."
|
||||
...
|
||||
C: .
|
||||
S: 250 message sent
|
||||
C: QUIT
|
||||
S: 221 goodbye
|
||||
|
||||
The client waits for a server response a total of 9 times in this
|
||||
simple example. But if pipelining is employed the following dialogue
|
||||
is possible:
|
||||
|
||||
S: <wait for open connection>
|
||||
C: <open connection to server>
|
||||
S: 220 innosoft.com SMTP service ready
|
||||
C: EHLO dbc.mtview.ca.us
|
||||
S: 250-innosoft.com
|
||||
S: 250 PIPELINING
|
||||
C: MAIL FROM:<mrose@dbc.mtview.ca.us>
|
||||
C: RCPT TO:<ned@innosoft.com>
|
||||
C: RCPT TO:<dan@innosoft.com>
|
||||
C: RCPT TO:<kvc@innosoft.com>
|
||||
C: DATA
|
||||
S: 250 sender <mrose@dbc.mtview.ca.us> OK
|
||||
S: 250 recipient <ned@innosoft.com> OK
|
||||
S: 250 recipient <dan@innosoft.com> OK
|
||||
S: 250 recipient <kvc@innosoft.com> OK
|
||||
|
||||
|
||||
|
||||
Freed & Cargille Standards Track [Page 5]
|
||||
|
||||
RFC 1854 SMTP Pipelining October 1995
|
||||
|
||||
|
||||
S: 354 enter mail, end with line containing only "."
|
||||
...
|
||||
C: .
|
||||
C: QUIT
|
||||
S: 250 message sent
|
||||
S: 221 goodbye
|
||||
|
||||
The total number of turnarounds has been reduced from 9 to 4.
|
||||
|
||||
The next example illustrates one possible form of behavior when
|
||||
pipelining is used and all recipients are rejected:
|
||||
|
||||
S: <wait for open connection>
|
||||
C: <open connection to server>
|
||||
S: 220 innosoft.com SMTP service ready
|
||||
C: EHLO dbc.mtview.ca.us
|
||||
S: 250-innosoft.com
|
||||
S: 250 PIPELINING
|
||||
C: MAIL FROM:<mrose@dbc.mtview.ca.us>
|
||||
C: RCPT TO:<nsb@thumper.bellcore.com>
|
||||
C: RCPT TO:<galvin@tis.com>
|
||||
C: DATA
|
||||
S: 250 sender <mrose@dbc.mtview.ca.us> OK
|
||||
S: 550 remote mail to <nsb@thumper.bellore.com> not allowed
|
||||
S: 550 remote mail to <galvin@tis.com> not allowed
|
||||
S: 554 no valid recipients given
|
||||
C: QUIT
|
||||
S: 221 goodbye
|
||||
|
||||
The client SMTP waits for the server 4 times here as well. If the
|
||||
server SMTP does not check for at least one valid recipient prior to
|
||||
accepting the DATA command, the following dialogue would result:
|
||||
|
||||
S: <wait for open connection>
|
||||
C: <open connection to server>
|
||||
S: 220 innosoft.com SMTP service ready
|
||||
C: EHLO dbc.mtview.ca.us
|
||||
S: 250-innosoft.com
|
||||
S: 250 PIPELINING
|
||||
C: MAIL FROM:<mrose@dbc.mtview.ca.us>
|
||||
C: RCPT TO:<nsb@thumper.bellcore.com>
|
||||
C: RCPT TO:<galvin@tis.com>
|
||||
C: DATA
|
||||
S: 250 sender <mrose@dbc.mtview.ca.us> OK
|
||||
S: 550 remote mail to <nsb@thumper.bellore.com> not allowed
|
||||
S: 550 remote mail to <galvin@tis.com> not allowed
|
||||
S: 354 enter mail, end with line containing only "."
|
||||
C: .
|
||||
|
||||
|
||||
|
||||
Freed & Cargille Standards Track [Page 6]
|
||||
|
||||
RFC 1854 SMTP Pipelining October 1995
|
||||
|
||||
|
||||
C: QUIT
|
||||
S: 554 no valid recipients
|
||||
S: 221 goodbye
|
||||
|
||||
4. Security Considerations
|
||||
|
||||
This RFC does not discuss security issues and is not believed to
|
||||
raise any security issues not endemic in electronic mail and present
|
||||
in fully conforming implementations of [1].
|
||||
|
||||
5. Acknowledgements
|
||||
|
||||
This document is based on the SMTP service extension model presented
|
||||
in RFC 1425. Marshall Rose's description of SMTP command pipelining
|
||||
in his book "The Internet Message" also served as a source of
|
||||
inspiration for this extension.
|
||||
|
||||
6. References
|
||||
|
||||
[1] Postel, J., "Simple Mail Transfer Protocol", STD 10
|
||||
RFC 821, USC/Information Sciences Institute, August
|
||||
1982.
|
||||
|
||||
[2] Klensin, J., Freed, N., Rose, M., Stefferud, E.,
|
||||
and D. Crocker, "SMTP Service Extensions", RFC 1651,
|
||||
MCI, Innosoft, Dover Beach Consulting, Inc.,
|
||||
Network Management Associates, Inc., Silicon Graphics,
|
||||
Inc., July 1994.
|
||||
|
||||
7. Author's Address
|
||||
|
||||
Ned Freed
|
||||
Innosoft International, Inc.
|
||||
1050 East Garvey Avenue South
|
||||
West Covina, CA 91790
|
||||
USA
|
||||
|
||||
Phone: +1 818 919 3600
|
||||
Fax: +1 818 919 3614
|
||||
EMail: ned@innosoft.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Cargille Standards Track [Page 7]
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,843 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group K. Moore
|
||||
Request for Comments: 2047 University of Tennessee
|
||||
Obsoletes: 1521, 1522, 1590 November 1996
|
||||
Category: Standards Track
|
||||
|
||||
|
||||
MIME (Multipurpose Internet Mail Extensions) Part Three:
|
||||
Message Header Extensions for Non-ASCII Text
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Abstract
|
||||
|
||||
STD 11, RFC 822, defines a message representation protocol specifying
|
||||
considerable detail about US-ASCII message headers, and leaves the
|
||||
message content, or message body, as flat US-ASCII text. This set of
|
||||
documents, collectively called the Multipurpose Internet Mail
|
||||
Extensions, or MIME, redefines the format of messages to allow for
|
||||
|
||||
(1) textual message bodies in character sets other than US-ASCII,
|
||||
|
||||
(2) an extensible set of different formats for non-textual message
|
||||
bodies,
|
||||
|
||||
(3) multi-part message bodies, and
|
||||
|
||||
(4) textual header information in character sets other than US-ASCII.
|
||||
|
||||
These documents are based on earlier work documented in RFC 934, STD
|
||||
11, and RFC 1049, but extends and revises them. Because RFC 822 said
|
||||
so little about message bodies, these documents are largely
|
||||
orthogonal to (rather than a revision of) RFC 822.
|
||||
|
||||
This particular document is the third document in the series. It
|
||||
describes extensions to RFC 822 to allow non-US-ASCII text data in
|
||||
Internet mail header fields.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 1]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
Other documents in this series include:
|
||||
|
||||
+ RFC 2045, which specifies the various headers used to describe
|
||||
the structure of MIME messages.
|
||||
|
||||
+ RFC 2046, which defines the general structure of the MIME media
|
||||
typing system and defines an initial set of media types,
|
||||
|
||||
+ RFC 2048, which specifies various IANA registration procedures
|
||||
for MIME-related facilities, and
|
||||
|
||||
+ RFC 2049, which describes MIME conformance criteria and
|
||||
provides some illustrative examples of MIME message formats,
|
||||
acknowledgements, and the bibliography.
|
||||
|
||||
These documents are revisions of RFCs 1521, 1522, and 1590, which
|
||||
themselves were revisions of RFCs 1341 and 1342. An appendix in RFC
|
||||
2049 describes differences and changes from previous versions.
|
||||
|
||||
1. Introduction
|
||||
|
||||
RFC 2045 describes a mechanism for denoting textual body parts which
|
||||
are coded in various character sets, as well as methods for encoding
|
||||
such body parts as sequences of printable US-ASCII characters. This
|
||||
memo describes similar techniques to allow the encoding of non-ASCII
|
||||
text in various portions of a RFC 822 [2] message header, in a manner
|
||||
which is unlikely to confuse existing message handling software.
|
||||
|
||||
Like the encoding techniques described in RFC 2045, the techniques
|
||||
outlined here were designed to allow the use of non-ASCII characters
|
||||
in message headers in a way which is unlikely to be disturbed by the
|
||||
quirks of existing Internet mail handling programs. In particular,
|
||||
some mail relaying programs are known to (a) delete some message
|
||||
header fields while retaining others, (b) rearrange the order of
|
||||
addresses in To or Cc fields, (c) rearrange the (vertical) order of
|
||||
header fields, and/or (d) "wrap" message headers at different places
|
||||
than those in the original message. In addition, some mail reading
|
||||
programs are known to have difficulty correctly parsing message
|
||||
headers which, while legal according to RFC 822, make use of
|
||||
backslash-quoting to "hide" special characters such as "<", ",", or
|
||||
":", or which exploit other infrequently-used features of that
|
||||
specification.
|
||||
|
||||
While it is unfortunate that these programs do not correctly
|
||||
interpret RFC 822 headers, to "break" these programs would cause
|
||||
severe operational problems for the Internet mail system. The
|
||||
extensions described in this memo therefore do not rely on little-
|
||||
used features of RFC 822.
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 2]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
Instead, certain sequences of "ordinary" printable ASCII characters
|
||||
(known as "encoded-words") are reserved for use as encoded data. The
|
||||
syntax of encoded-words is such that they are unlikely to
|
||||
"accidentally" appear as normal text in message headers.
|
||||
Furthermore, the characters used in encoded-words are restricted to
|
||||
those which do not have special meanings in the context in which the
|
||||
encoded-word appears.
|
||||
|
||||
Generally, an "encoded-word" is a sequence of printable ASCII
|
||||
characters that begins with "=?", ends with "?=", and has two "?"s in
|
||||
between. It specifies a character set and an encoding method, and
|
||||
also includes the original text encoded as graphic ASCII characters,
|
||||
according to the rules for that encoding method.
|
||||
|
||||
A mail composer that implements this specification will provide a
|
||||
means of inputting non-ASCII text in header fields, but will
|
||||
translate these fields (or appropriate portions of these fields) into
|
||||
encoded-words before inserting them into the message header.
|
||||
|
||||
A mail reader that implements this specification will recognize
|
||||
encoded-words when they appear in certain portions of the message
|
||||
header. Instead of displaying the encoded-word "as is", it will
|
||||
reverse the encoding and display the original text in the designated
|
||||
character set.
|
||||
|
||||
NOTES
|
||||
|
||||
This memo relies heavily on notation and terms defined RFC 822 and
|
||||
RFC 2045. In particular, the syntax for the ABNF used in this memo
|
||||
is defined in RFC 822, as well as many of the terminal or nonterminal
|
||||
symbols from RFC 822 are used in the grammar for the header
|
||||
extensions defined here. Among the symbols defined in RFC 822 and
|
||||
referenced in this memo are: 'addr-spec', 'atom', 'CHAR', 'comment',
|
||||
'CTLs', 'ctext', 'linear-white-space', 'phrase', 'quoted-pair'.
|
||||
'quoted-string', 'SPACE', and 'word'. Successful implementation of
|
||||
this protocol extension requires careful attention to the RFC 822
|
||||
definitions of these terms.
|
||||
|
||||
When the term "ASCII" appears in this memo, it refers to the "7-Bit
|
||||
American Standard Code for Information Interchange", ANSI X3.4-1986.
|
||||
The MIME charset name for this character set is "US-ASCII". When not
|
||||
specifically referring to the MIME charset name, this document uses
|
||||
the term "ASCII", both for brevity and for consistency with RFC 822.
|
||||
However, implementors are warned that the character set name must be
|
||||
spelled "US-ASCII" in MIME message and body part headers.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 3]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
This memo specifies a protocol for the representation of non-ASCII
|
||||
text in message headers. It specifically DOES NOT define any
|
||||
translation between "8-bit headers" and pure ASCII headers, nor is
|
||||
any such translation assumed to be possible.
|
||||
|
||||
2. Syntax of encoded-words
|
||||
|
||||
An 'encoded-word' is defined by the following ABNF grammar. The
|
||||
notation of RFC 822 is used, with the exception that white space
|
||||
characters MUST NOT appear between components of an 'encoded-word'.
|
||||
|
||||
encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
|
||||
|
||||
charset = token ; see section 3
|
||||
|
||||
encoding = token ; see section 4
|
||||
|
||||
token = 1*<Any CHAR except SPACE, CTLs, and especials>
|
||||
|
||||
especials = "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "
|
||||
<"> / "/" / "[" / "]" / "?" / "." / "="
|
||||
|
||||
encoded-text = 1*<Any printable ASCII character other than "?"
|
||||
or SPACE>
|
||||
; (but see "Use of encoded-words in message
|
||||
; headers", section 5)
|
||||
|
||||
Both 'encoding' and 'charset' names are case-independent. Thus the
|
||||
charset name "ISO-8859-1" is equivalent to "iso-8859-1", and the
|
||||
encoding named "Q" may be spelled either "Q" or "q".
|
||||
|
||||
An 'encoded-word' may not be more than 75 characters long, including
|
||||
'charset', 'encoding', 'encoded-text', and delimiters. If it is
|
||||
desirable to encode more text than will fit in an 'encoded-word' of
|
||||
75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may
|
||||
be used.
|
||||
|
||||
While there is no limit to the length of a multiple-line header
|
||||
field, each line of a header field that contains one or more
|
||||
'encoded-word's is limited to 76 characters.
|
||||
|
||||
The length restrictions are included both to ease interoperability
|
||||
through internetwork mail gateways, and to impose a limit on the
|
||||
amount of lookahead a header parser must employ (while looking for a
|
||||
final ?= delimiter) before it can decide whether a token is an
|
||||
"encoded-word" or something else.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 4]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
IMPORTANT: 'encoded-word's are designed to be recognized as 'atom's
|
||||
by an RFC 822 parser. As a consequence, unencoded white space
|
||||
characters (such as SPACE and HTAB) are FORBIDDEN within an
|
||||
'encoded-word'. For example, the character sequence
|
||||
|
||||
=?iso-8859-1?q?this is some text?=
|
||||
|
||||
would be parsed as four 'atom's, rather than as a single 'atom' (by
|
||||
an RFC 822 parser) or 'encoded-word' (by a parser which understands
|
||||
'encoded-words'). The correct way to encode the string "this is some
|
||||
text" is to encode the SPACE characters as well, e.g.
|
||||
|
||||
=?iso-8859-1?q?this=20is=20some=20text?=
|
||||
|
||||
The characters which may appear in 'encoded-text' are further
|
||||
restricted by the rules in section 5.
|
||||
|
||||
3. Character sets
|
||||
|
||||
The 'charset' portion of an 'encoded-word' specifies the character
|
||||
set associated with the unencoded text. A 'charset' can be any of
|
||||
the character set names allowed in an MIME "charset" parameter of a
|
||||
"text/plain" body part, or any character set name registered with
|
||||
IANA for use with the MIME text/plain content-type.
|
||||
|
||||
Some character sets use code-switching techniques to switch between
|
||||
"ASCII mode" and other modes. If unencoded text in an 'encoded-word'
|
||||
contains a sequence which causes the charset interpreter to switch
|
||||
out of ASCII mode, it MUST contain additional control codes such that
|
||||
ASCII mode is again selected at the end of the 'encoded-word'. (This
|
||||
rule applies separately to each 'encoded-word', including adjacent
|
||||
'encoded-word's within a single header field.)
|
||||
|
||||
When there is a possibility of using more than one character set to
|
||||
represent the text in an 'encoded-word', and in the absence of
|
||||
private agreements between sender and recipients of a message, it is
|
||||
recommended that members of the ISO-8859-* series be used in
|
||||
preference to other character sets.
|
||||
|
||||
4. Encodings
|
||||
|
||||
Initially, the legal values for "encoding" are "Q" and "B". These
|
||||
encodings are described below. The "Q" encoding is recommended for
|
||||
use when most of the characters to be encoded are in the ASCII
|
||||
character set; otherwise, the "B" encoding should be used.
|
||||
Nevertheless, a mail reader which claims to recognize 'encoded-word's
|
||||
MUST be able to accept either encoding for any character set which it
|
||||
supports.
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 5]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
Only a subset of the printable ASCII characters may be used in
|
||||
'encoded-text'. Space and tab characters are not allowed, so that
|
||||
the beginning and end of an 'encoded-word' are obvious. The "?"
|
||||
character is used within an 'encoded-word' to separate the various
|
||||
portions of the 'encoded-word' from one another, and thus cannot
|
||||
appear in the 'encoded-text' portion. Other characters are also
|
||||
illegal in certain contexts. For example, an 'encoded-word' in a
|
||||
'phrase' preceding an address in a From header field may not contain
|
||||
any of the "specials" defined in RFC 822. Finally, certain other
|
||||
characters are disallowed in some contexts, to ensure reliability for
|
||||
messages that pass through internetwork mail gateways.
|
||||
|
||||
The "B" encoding automatically meets these requirements. The "Q"
|
||||
encoding allows a wide range of printable characters to be used in
|
||||
non-critical locations in the message header (e.g., Subject), with
|
||||
fewer characters available for use in other locations.
|
||||
|
||||
4.1. The "B" encoding
|
||||
|
||||
The "B" encoding is identical to the "BASE64" encoding defined by RFC
|
||||
2045.
|
||||
|
||||
4.2. The "Q" encoding
|
||||
|
||||
The "Q" encoding is similar to the "Quoted-Printable" content-
|
||||
transfer-encoding defined in RFC 2045. It is designed to allow text
|
||||
containing mostly ASCII characters to be decipherable on an ASCII
|
||||
terminal without decoding.
|
||||
|
||||
(1) Any 8-bit value may be represented by a "=" followed by two
|
||||
hexadecimal digits. For example, if the character set in use
|
||||
were ISO-8859-1, the "=" character would thus be encoded as
|
||||
"=3D", and a SPACE by "=20". (Upper case should be used for
|
||||
hexadecimal digits "A" through "F".)
|
||||
|
||||
(2) The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be
|
||||
represented as "_" (underscore, ASCII 95.). (This character may
|
||||
not pass through some internetwork mail gateways, but its use
|
||||
will greatly enhance readability of "Q" encoded data with mail
|
||||
readers that do not support this encoding.) Note that the "_"
|
||||
always represents hexadecimal 20, even if the SPACE character
|
||||
occupies a different code position in the character set in use.
|
||||
|
||||
(3) 8-bit values which correspond to printable ASCII characters other
|
||||
than "=", "?", and "_" (underscore), MAY be represented as those
|
||||
characters. (But see section 5 for restrictions.) In
|
||||
particular, SPACE and TAB MUST NOT be represented as themselves
|
||||
within encoded words.
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 6]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
5. Use of encoded-words in message headers
|
||||
|
||||
An 'encoded-word' may appear in a message header or body part header
|
||||
according to the following rules:
|
||||
|
||||
(1) An 'encoded-word' may replace a 'text' token (as defined by RFC 822)
|
||||
in any Subject or Comments header field, any extension message
|
||||
header field, or any MIME body part field for which the field body
|
||||
is defined as '*text'. An 'encoded-word' may also appear in any
|
||||
user-defined ("X-") message or body part header field.
|
||||
|
||||
Ordinary ASCII text and 'encoded-word's may appear together in the
|
||||
same header field. However, an 'encoded-word' that appears in a
|
||||
header field defined as '*text' MUST be separated from any adjacent
|
||||
'encoded-word' or 'text' by 'linear-white-space'.
|
||||
|
||||
(2) An 'encoded-word' may appear within a 'comment' delimited by "(" and
|
||||
")", i.e., wherever a 'ctext' is allowed. More precisely, the RFC
|
||||
822 ABNF definition for 'comment' is amended as follows:
|
||||
|
||||
comment = "(" *(ctext / quoted-pair / comment / encoded-word) ")"
|
||||
|
||||
A "Q"-encoded 'encoded-word' which appears in a 'comment' MUST NOT
|
||||
contain the characters "(", ")" or "
|
||||
'encoded-word' that appears in a 'comment' MUST be separated from
|
||||
any adjacent 'encoded-word' or 'ctext' by 'linear-white-space'.
|
||||
|
||||
It is important to note that 'comment's are only recognized inside
|
||||
"structured" field bodies. In fields whose bodies are defined as
|
||||
'*text', "(" and ")" are treated as ordinary characters rather than
|
||||
comment delimiters, and rule (1) of this section applies. (See RFC
|
||||
822, sections 3.1.2 and 3.1.3)
|
||||
|
||||
(3) As a replacement for a 'word' entity within a 'phrase', for example,
|
||||
one that precedes an address in a From, To, or Cc header. The ABNF
|
||||
definition for 'phrase' from RFC 822 thus becomes:
|
||||
|
||||
phrase = 1*( encoded-word / word )
|
||||
|
||||
In this case the set of characters that may be used in a "Q"-encoded
|
||||
'encoded-word' is restricted to: <upper and lower case ASCII
|
||||
letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
|
||||
(underscore, ASCII 95.)>. An 'encoded-word' that appears within a
|
||||
'phrase' MUST be separated from any adjacent 'word', 'text' or
|
||||
'special' by 'linear-white-space'.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 7]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
These are the ONLY locations where an 'encoded-word' may appear. In
|
||||
particular:
|
||||
|
||||
+ An 'encoded-word' MUST NOT appear in any portion of an 'addr-spec'.
|
||||
|
||||
+ An 'encoded-word' MUST NOT appear within a 'quoted-string'.
|
||||
|
||||
+ An 'encoded-word' MUST NOT be used in a Received header field.
|
||||
|
||||
+ An 'encoded-word' MUST NOT be used in parameter of a MIME
|
||||
Content-Type or Content-Disposition field, or in any structured
|
||||
field body except within a 'comment' or 'phrase'.
|
||||
|
||||
The 'encoded-text' in an 'encoded-word' must be self-contained;
|
||||
'encoded-text' MUST NOT be continued from one 'encoded-word' to
|
||||
another. This implies that the 'encoded-text' portion of a "B"
|
||||
'encoded-word' will be a multiple of 4 characters long; for a "Q"
|
||||
'encoded-word', any "=" character that appears in the 'encoded-text'
|
||||
portion will be followed by two hexadecimal characters.
|
||||
|
||||
Each 'encoded-word' MUST encode an integral number of octets. The
|
||||
'encoded-text' in each 'encoded-word' must be well-formed according
|
||||
to the encoding specified; the 'encoded-text' may not be continued in
|
||||
the next 'encoded-word'. (For example, "=?charset?Q?=?=
|
||||
=?charset?Q?AB?=" would be illegal, because the two hex digits "AB"
|
||||
must follow the "=" in the same 'encoded-word'.)
|
||||
|
||||
Each 'encoded-word' MUST represent an integral number of characters.
|
||||
A multi-octet character may not be split across adjacent 'encoded-
|
||||
word's.
|
||||
|
||||
Only printable and white space character data should be encoded using
|
||||
this scheme. However, since these encoding schemes allow the
|
||||
encoding of arbitrary octet values, mail readers that implement this
|
||||
decoding should also ensure that display of the decoded data on the
|
||||
recipient's terminal will not cause unwanted side-effects.
|
||||
|
||||
Use of these methods to encode non-textual data (e.g., pictures or
|
||||
sounds) is not defined by this memo. Use of 'encoded-word's to
|
||||
represent strings of purely ASCII characters is allowed, but
|
||||
discouraged. In rare cases it may be necessary to encode ordinary
|
||||
text that looks like an 'encoded-word'.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 8]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
6. Support of 'encoded-word's by mail readers
|
||||
|
||||
6.1. Recognition of 'encoded-word's in message headers
|
||||
|
||||
A mail reader must parse the message and body part headers according
|
||||
to the rules in RFC 822 to correctly recognize 'encoded-word's.
|
||||
|
||||
'encoded-word's are to be recognized as follows:
|
||||
|
||||
(1) Any message or body part header field defined as '*text', or any
|
||||
user-defined header field, should be parsed as follows: Beginning
|
||||
at the start of the field-body and immediately following each
|
||||
occurrence of 'linear-white-space', each sequence of up to 75
|
||||
printable characters (not containing any 'linear-white-space')
|
||||
should be examined to see if it is an 'encoded-word' according to
|
||||
the syntax rules in section 2. Any other sequence of printable
|
||||
characters should be treated as ordinary ASCII text.
|
||||
|
||||
(2) Any header field not defined as '*text' should be parsed
|
||||
according to the syntax rules for that header field. However,
|
||||
any 'word' that appears within a 'phrase' should be treated as an
|
||||
'encoded-word' if it meets the syntax rules in section 2.
|
||||
Otherwise it should be treated as an ordinary 'word'.
|
||||
|
||||
(3) Within a 'comment', any sequence of up to 75 printable characters
|
||||
(not containing 'linear-white-space'), that meets the syntax
|
||||
rules in section 2, should be treated as an 'encoded-word'.
|
||||
Otherwise it should be treated as normal comment text.
|
||||
|
||||
(4) A MIME-Version header field is NOT required to be present for
|
||||
'encoded-word's to be interpreted according to this
|
||||
specification. One reason for this is that the mail reader is
|
||||
not expected to parse the entire message header before displaying
|
||||
lines that may contain 'encoded-word's.
|
||||
|
||||
6.2. Display of 'encoded-word's
|
||||
|
||||
Any 'encoded-word's so recognized are decoded, and if possible, the
|
||||
resulting unencoded text is displayed in the original character set.
|
||||
|
||||
NOTE: Decoding and display of encoded-words occurs *after* a
|
||||
structured field body is parsed into tokens. It is therefore
|
||||
possible to hide 'special' characters in encoded-words which, when
|
||||
displayed, will be indistinguishable from 'special' characters in the
|
||||
surrounding text. For this and other reasons, it is NOT generally
|
||||
possible to translate a message header containing 'encoded-word's to
|
||||
an unencoded form which can be parsed by an RFC 822 mail reader.
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 9]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
When displaying a particular header field that contains multiple
|
||||
'encoded-word's, any 'linear-white-space' that separates a pair of
|
||||
adjacent 'encoded-word's is ignored. (This is to allow the use of
|
||||
multiple 'encoded-word's to represent long strings of unencoded text,
|
||||
without having to separate 'encoded-word's where spaces occur in the
|
||||
unencoded text.)
|
||||
|
||||
In the event other encodings are defined in the future, and the mail
|
||||
reader does not support the encoding used, it may either (a) display
|
||||
the 'encoded-word' as ordinary text, or (b) substitute an appropriate
|
||||
message indicating that the text could not be decoded.
|
||||
|
||||
If the mail reader does not support the character set used, it may
|
||||
(a) display the 'encoded-word' as ordinary text (i.e., as it appears
|
||||
in the header), (b) make a "best effort" to display using such
|
||||
characters as are available, or (c) substitute an appropriate message
|
||||
indicating that the decoded text could not be displayed.
|
||||
|
||||
If the character set being used employs code-switching techniques,
|
||||
display of the encoded text implicitly begins in "ASCII mode". In
|
||||
addition, the mail reader must ensure that the output device is once
|
||||
again in "ASCII mode" after the 'encoded-word' is displayed.
|
||||
|
||||
6.3. Mail reader handling of incorrectly formed 'encoded-word's
|
||||
|
||||
It is possible that an 'encoded-word' that is legal according to the
|
||||
syntax defined in section 2, is incorrectly formed according to the
|
||||
rules for the encoding being used. For example:
|
||||
|
||||
(1) An 'encoded-word' which contains characters which are not legal
|
||||
for a particular encoding (for example, a "-" in the "B"
|
||||
encoding, or a SPACE or HTAB in either the "B" or "Q" encoding),
|
||||
is incorrectly formed.
|
||||
|
||||
(2) Any 'encoded-word' which encodes a non-integral number of
|
||||
characters or octets is incorrectly formed.
|
||||
|
||||
A mail reader need not attempt to display the text associated with an
|
||||
'encoded-word' that is incorrectly formed. However, a mail reader
|
||||
MUST NOT prevent the display or handling of a message because an
|
||||
'encoded-word' is incorrectly formed.
|
||||
|
||||
7. Conformance
|
||||
|
||||
A mail composing program claiming compliance with this specification
|
||||
MUST ensure that any string of non-white-space printable ASCII
|
||||
characters within a '*text' or '*ctext' that begins with "=?" and
|
||||
ends with "?=" be a valid 'encoded-word'. ("begins" means: at the
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 10]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
start of the field-body, immediately following 'linear-white-space',
|
||||
or immediately following a "(" for an 'encoded-word' within '*ctext';
|
||||
"ends" means: at the end of the field-body, immediately preceding
|
||||
'linear-white-space', or immediately preceding a ")" for an
|
||||
'encoded-word' within '*ctext'.) In addition, any 'word' within a
|
||||
'phrase' that begins with "=?" and ends with "?=" must be a valid
|
||||
'encoded-word'.
|
||||
|
||||
A mail reading program claiming compliance with this specification
|
||||
must be able to distinguish 'encoded-word's from 'text', 'ctext', or
|
||||
'word's, according to the rules in section 6, anytime they appear in
|
||||
appropriate places in message headers. It must support both the "B"
|
||||
and "Q" encodings for any character set which it supports. The
|
||||
program must be able to display the unencoded text if the character
|
||||
set is "US-ASCII". For the ISO-8859-* character sets, the mail
|
||||
reading program must at least be able to display the characters which
|
||||
are also in the ASCII set.
|
||||
|
||||
8. Examples
|
||||
|
||||
The following are examples of message headers containing 'encoded-
|
||||
word's:
|
||||
|
||||
From: =?US-ASCII?Q?Keith_Moore?= <moore@cs.utk.edu>
|
||||
To: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= <keld@dkuug.dk>
|
||||
CC: =?ISO-8859-1?Q?Andr=E9?= Pirard <PIRARD@vm1.ulg.ac.be>
|
||||
Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=
|
||||
=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=
|
||||
|
||||
Note: In the first 'encoded-word' of the Subject field above, the
|
||||
last "=" at the end of the 'encoded-text' is necessary because each
|
||||
'encoded-word' must be self-contained (the "=" character completes a
|
||||
group of 4 base64 characters representing 2 octets). An additional
|
||||
octet could have been encoded in the first 'encoded-word' (so that
|
||||
the encoded-word would contain an exact multiple of 3 encoded
|
||||
octets), except that the second 'encoded-word' uses a different
|
||||
'charset' than the first one.
|
||||
|
||||
From: =?ISO-8859-1?Q?Olle_J=E4rnefors?= <ojarnef@admin.kth.se>
|
||||
To: ietf-822@dimacs.rutgers.edu, ojarnef@admin.kth.se
|
||||
Subject: Time for ISO 10646?
|
||||
|
||||
To: Dave Crocker <dcrocker@mordor.stanford.edu>
|
||||
Cc: ietf-822@dimacs.rutgers.edu, paf@comsol.se
|
||||
From: =?ISO-8859-1?Q?Patrik_F=E4ltstr=F6m?= <paf@nada.kth.se>
|
||||
Subject: Re: RFC-HDR care and feeding
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 11]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
From: Nathaniel Borenstein <nsb@thumper.bellcore.com>
|
||||
(=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?=)
|
||||
To: Greg Vaudreuil <gvaudre@NRI.Reston.VA.US>, Ned Freed
|
||||
<ned@innosoft.com>, Keith Moore <moore@cs.utk.edu>
|
||||
Subject: Test of new header generator
|
||||
MIME-Version: 1.0
|
||||
Content-type: text/plain; charset=ISO-8859-1
|
||||
|
||||
The following examples illustrate how text containing 'encoded-word's
|
||||
which appear in a structured field body. The rules are slightly
|
||||
different for fields defined as '*text' because "(" and ")" are not
|
||||
recognized as 'comment' delimiters. [Section 5, paragraph (1)].
|
||||
|
||||
In each of the following examples, if the same sequence were to occur
|
||||
in a '*text' field, the "displayed as" form would NOT be treated as
|
||||
encoded words, but be identical to the "encoded form". This is
|
||||
because each of the encoded-words in the following examples is
|
||||
adjacent to a "(" or ")" character.
|
||||
|
||||
encoded form displayed as
|
||||
---------------------------------------------------------------------
|
||||
(=?ISO-8859-1?Q?a?=) (a)
|
||||
|
||||
(=?ISO-8859-1?Q?a?= b) (a b)
|
||||
|
||||
Within a 'comment', white space MUST appear between an
|
||||
'encoded-word' and surrounding text. [Section 5,
|
||||
paragraph (2)]. However, white space is not needed between
|
||||
the initial "(" that begins the 'comment', and the
|
||||
'encoded-word'.
|
||||
|
||||
|
||||
(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=) (ab)
|
||||
|
||||
White space between adjacent 'encoded-word's is not
|
||||
displayed.
|
||||
|
||||
(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=) (ab)
|
||||
|
||||
Even multiple SPACEs between 'encoded-word's are ignored
|
||||
for the purpose of display.
|
||||
|
||||
(=?ISO-8859-1?Q?a?= (ab)
|
||||
=?ISO-8859-1?Q?b?=)
|
||||
|
||||
Any amount of linear-space-white between 'encoded-word's,
|
||||
even if it includes a CRLF followed by one or more SPACEs,
|
||||
is ignored for the purposes of display.
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 12]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
(=?ISO-8859-1?Q?a_b?=) (a b)
|
||||
|
||||
In order to cause a SPACE to be displayed within a portion
|
||||
of encoded text, the SPACE MUST be encoded as part of the
|
||||
'encoded-word'.
|
||||
|
||||
(=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?=) (a b)
|
||||
|
||||
In order to cause a SPACE to be displayed between two strings
|
||||
of encoded text, the SPACE MAY be encoded as part of one of
|
||||
the 'encoded-word's.
|
||||
|
||||
9. References
|
||||
|
||||
[RFC 822] Crocker, D., "Standard for the Format of ARPA Internet Text
|
||||
Messages", STD 11, RFC 822, UDEL, August 1982.
|
||||
|
||||
[RFC 2049] Borenstein, N., and N. Freed, "Multipurpose Internet Mail
|
||||
Extensions (MIME) Part Five: Conformance Criteria and Examples",
|
||||
RFC 2049, November 1996.
|
||||
|
||||
[RFC 2045] Borenstein, N., and N. Freed, "Multipurpose Internet Mail
|
||||
Extensions (MIME) Part One: Format of Internet Message Bodies",
|
||||
RFC 2045, November 1996.
|
||||
|
||||
[RFC 2046] Borenstein N., and N. Freed, "Multipurpose Internet Mail
|
||||
Extensions (MIME) Part Two: Media Types", RFC 2046,
|
||||
November 1996.
|
||||
|
||||
[RFC 2048] Freed, N., Klensin, J., and J. Postel, "Multipurpose
|
||||
Internet Mail Extensions (MIME) Part Four: Registration
|
||||
Procedures", RFC 2048, November 1996.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 13]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
10. Security Considerations
|
||||
|
||||
Security issues are not discussed in this memo.
|
||||
|
||||
11. Acknowledgements
|
||||
|
||||
The author wishes to thank Nathaniel Borenstein, Issac Chan, Lutz
|
||||
Donnerhacke, Paul Eggert, Ned Freed, Andreas M. Kirchwitz, Olle
|
||||
Jarnefors, Mike Rosin, Yutaka Sato, Bart Schaefer, and Kazuhiko
|
||||
Yamamoto, for their helpful advice, insightful comments, and
|
||||
illuminating questions in response to earlier versions of this
|
||||
specification.
|
||||
|
||||
12. Author's Address
|
||||
|
||||
Keith Moore
|
||||
University of Tennessee
|
||||
107 Ayres Hall
|
||||
Knoxville TN 37996-1301
|
||||
|
||||
EMail: moore@cs.utk.edu
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 14]
|
||||
|
||||
RFC 2047 Message Header Extensions November 1996
|
||||
|
||||
|
||||
Appendix - changes since RFC 1522 (in no particular order)
|
||||
|
||||
+ explicitly state that the MIME-Version is not requried to use
|
||||
'encoded-word's.
|
||||
|
||||
+ add explicit note that SPACEs and TABs are not allowed within
|
||||
'encoded-word's, explaining that an 'encoded-word' must look like an
|
||||
'atom' to an RFC822 parser.values, to be precise).
|
||||
|
||||
+ add examples from Olle Jarnefors (thanks!) which illustrate how
|
||||
encoded-words with adjacent linear-white-space are displayed.
|
||||
|
||||
+ explicitly list terms defined in RFC822 and referenced in this memo
|
||||
|
||||
+ fix transcription typos that caused one or two lines and a couple of
|
||||
characters to disappear in the resulting text, due to nroff quirks.
|
||||
|
||||
+ clarify that encoded-words are allowed in '*text' fields in both
|
||||
RFC822 headers and MIME body part headers, but NOT as parameter
|
||||
values.
|
||||
|
||||
+ clarify the requirement to switch back to ASCII within the encoded
|
||||
portion of an 'encoded-word', for any charset that uses code switching
|
||||
sequences.
|
||||
|
||||
+ add a note about 'encoded-word's being delimited by "(" and ")"
|
||||
within a comment, but not in a *text (how bizarre!).
|
||||
|
||||
+ fix the Andre Pirard example to get rid of the trailing "_" after
|
||||
the =E9. (no longer needed post-1342).
|
||||
|
||||
+ clarification: an 'encoded-word' may appear immediately following
|
||||
the initial "(" or immediately before the final ")" that delimits a
|
||||
comment, not just adjacent to "(" and ")" *within* *ctext.
|
||||
|
||||
+ add a note to explain that a "B" 'encoded-word' will always have a
|
||||
multiple of 4 characters in the 'encoded-text' portion.
|
||||
|
||||
+ add note about the "=" in the examples
|
||||
|
||||
+ note that processing of 'encoded-word's occurs *after* parsing, and
|
||||
some of the implications thereof.
|
||||
|
||||
+ explicitly state that you can't expect to translate between
|
||||
1522 and either vanilla 822 or so-called "8-bit headers".
|
||||
|
||||
+ explicitly state that 'encoded-word's are not valid within a
|
||||
'quoted-string'.
|
||||
|
||||
|
||||
|
||||
Moore Standards Track [Page 15]
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,675 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group R. Troost
|
||||
Request for Comments: 2183 New Century Systems
|
||||
Updates: 1806 S. Dorner
|
||||
Category: Standards Track QUALCOMM Incorporated
|
||||
K. Moore, Editor
|
||||
University of Tennessee
|
||||
August 1997
|
||||
|
||||
|
||||
Communicating Presentation Information in
|
||||
Internet Messages:
|
||||
The Content-Disposition Header Field
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Abstract
|
||||
|
||||
This memo provides a mechanism whereby messages conforming to the
|
||||
MIME specifications [RFC 2045, RFC 2046, RFC 2047, RFC 2048, RFC
|
||||
2049] can convey presentational information. It specifies the
|
||||
"Content-Disposition" header field, which is optional and valid for
|
||||
any MIME entity ("message" or "body part"). Two values for this
|
||||
header field are described in this memo; one for the ordinary linear
|
||||
presentation of the body part, and another to facilitate the use of
|
||||
mail to transfer files. It is expected that more values will be
|
||||
defined in the future, and procedures are defined for extending this
|
||||
set of values.
|
||||
|
||||
This document is intended as an extension to MIME. As such, the
|
||||
reader is assumed to be familiar with the MIME specifications, and
|
||||
[RFC 822]. The information presented herein supplements but does not
|
||||
replace that found in those documents.
|
||||
|
||||
This document is a revision to the Experimental protocol defined in
|
||||
RFC 1806. As compared to RFC 1806, this document contains minor
|
||||
editorial updates, adds new parameters needed to support the File
|
||||
Transfer Body Part, and references a separate specification for the
|
||||
handling of non-ASCII and/or very long parameter values.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 1]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
MIME specifies a standard format for encapsulating multiple pieces of
|
||||
data into a single Internet message. That document does not address
|
||||
the issue of presentation styles; it provides a framework for the
|
||||
interchange of message content, but leaves presentation issues solely
|
||||
in the hands of mail user agent (MUA) implementors.
|
||||
|
||||
Two common ways of presenting multipart electronic messages are as a
|
||||
main document with a list of separate attachments, and as a single
|
||||
document with the various parts expanded (displayed) inline. The
|
||||
display of an attachment is generally construed to require positive
|
||||
action on the part of the recipient, while inline message components
|
||||
are displayed automatically when the message is viewed. A mechanism
|
||||
is needed to allow the sender to transmit this sort of presentational
|
||||
information to the recipient; the Content-Disposition header provides
|
||||
this mechanism, allowing each component of a message to be tagged
|
||||
with an indication of its desired presentation semantics.
|
||||
|
||||
Tagging messages in this manner will often be sufficient for basic
|
||||
message formatting. However, in many cases a more powerful and
|
||||
flexible approach will be necessary. The definition of such
|
||||
approaches is beyond the scope of this memo; however, such approaches
|
||||
can benefit from additional Content-Disposition values and
|
||||
parameters, to be defined at a later date.
|
||||
|
||||
In addition to allowing the sender to specify the presentational
|
||||
disposition of a message component, it is desirable to allow her to
|
||||
indicate a default archival disposition; a filename. The optional
|
||||
"filename" parameter provides for this. Further, the creation-date,
|
||||
modification-date, and read-date parameters allow preservation of
|
||||
those file attributes when the file is transmitted over MIME email.
|
||||
|
||||
NB: The keywords MUST, MUST NOT, REQUIRED, SHALL, SHALL NOT, SHOULD,
|
||||
SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL, when they appear in this
|
||||
document, are to be interpreted as described in [RFC 2119].
|
||||
|
||||
2. The Content-Disposition Header Field
|
||||
|
||||
Content-Disposition is an optional header field. In its absence, the
|
||||
MUA may use whatever presentation method it deems suitable.
|
||||
|
||||
It is desirable to keep the set of possible disposition types small
|
||||
and well defined, to avoid needless complexity. Even so, evolving
|
||||
usage will likely require the definition of additional disposition
|
||||
types or parameters, so the set of disposition values is extensible;
|
||||
see below.
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 2]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
In the extended BNF notation of [RFC 822], the Content-Disposition
|
||||
header field is defined as follows:
|
||||
|
||||
disposition := "Content-Disposition" ":"
|
||||
disposition-type
|
||||
*(";" disposition-parm)
|
||||
|
||||
disposition-type := "inline"
|
||||
/ "attachment"
|
||||
/ extension-token
|
||||
; values are not case-sensitive
|
||||
|
||||
disposition-parm := filename-parm
|
||||
/ creation-date-parm
|
||||
/ modification-date-parm
|
||||
/ read-date-parm
|
||||
/ size-parm
|
||||
/ parameter
|
||||
|
||||
filename-parm := "filename" "=" value
|
||||
|
||||
creation-date-parm := "creation-date" "=" quoted-date-time
|
||||
|
||||
modification-date-parm := "modification-date" "=" quoted-date-time
|
||||
|
||||
read-date-parm := "read-date" "=" quoted-date-time
|
||||
|
||||
size-parm := "size" "=" 1*DIGIT
|
||||
|
||||
quoted-date-time := quoted-string
|
||||
; contents MUST be an RFC 822 `date-time'
|
||||
; numeric timezones (+HHMM or -HHMM) MUST be used
|
||||
|
||||
|
||||
|
||||
NOTE ON PARAMETER VALUE LENGHTS: A short (length <= 78 characters)
|
||||
parameter value containing only non-`tspecials' characters SHOULD be
|
||||
represented as a single `token'. A short parameter value containing
|
||||
only ASCII characters, but including `tspecials' characters, SHOULD
|
||||
be represented as `quoted-string'. Parameter values longer than 78
|
||||
characters, or which contain non-ASCII characters, MUST be encoded as
|
||||
specified in [RFC 2184].
|
||||
|
||||
`Extension-token', `parameter', `tspecials' and `value' are defined
|
||||
according to [RFC 2045] (which references [RFC 822] in the definition
|
||||
of some of these tokens). `quoted-string' and `DIGIT' are defined in
|
||||
[RFC 822].
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 3]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
2.1 The Inline Disposition Type
|
||||
|
||||
A bodypart should be marked `inline' if it is intended to be
|
||||
displayed automatically upon display of the message. Inline
|
||||
bodyparts should be presented in the order in which they occur,
|
||||
subject to the normal semantics of multipart messages.
|
||||
|
||||
2.2 The Attachment Disposition Type
|
||||
|
||||
Bodyparts can be designated `attachment' to indicate that they are
|
||||
separate from the main body of the mail message, and that their
|
||||
display should not be automatic, but contingent upon some further
|
||||
action of the user. The MUA might instead present the user of a
|
||||
bitmap terminal with an iconic representation of the attachments, or,
|
||||
on character terminals, with a list of attachments from which the
|
||||
user could select for viewing or storage.
|
||||
|
||||
2.3 The Filename Parameter
|
||||
|
||||
The sender may want to suggest a filename to be used if the entity is
|
||||
detached and stored in a separate file. If the receiving MUA writes
|
||||
the entity to a file, the suggested filename should be used as a
|
||||
basis for the actual filename, where possible.
|
||||
|
||||
It is important that the receiving MUA not blindly use the suggested
|
||||
filename. The suggested filename SHOULD be checked (and possibly
|
||||
changed) to see that it conforms to local filesystem conventions,
|
||||
does not overwrite an existing file, and does not present a security
|
||||
problem (see Security Considerations below).
|
||||
|
||||
The receiving MUA SHOULD NOT respect any directory path information
|
||||
that may seem to be present in the filename parameter. The filename
|
||||
should be treated as a terminal component only. Portable
|
||||
specification of directory paths might possibly be done in the future
|
||||
via a separate Content-Disposition parameter, but no provision is
|
||||
made for it in this draft.
|
||||
|
||||
Current [RFC 2045] grammar restricts parameter values (and hence
|
||||
Content-Disposition filenames) to US-ASCII. We recognize the great
|
||||
desirability of allowing arbitrary character sets in filenames, but
|
||||
it is beyond the scope of this document to define the necessary
|
||||
mechanisms. We expect that the basic [RFC 1521] `value'
|
||||
specification will someday be amended to allow use of non-US-ASCII
|
||||
characters, at which time the same mechanism should be used in the
|
||||
Content-Disposition filename parameter.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 4]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
Beyond the limitation to US-ASCII, the sending MUA may wish to bear
|
||||
in mind the limitations of common filesystems. Many have severe
|
||||
length and character set restrictions. Short alphanumeric filenames
|
||||
are least likely to require modification by the receiving system.
|
||||
|
||||
The presence of the filename parameter does not force an
|
||||
implementation to write the entity to a separate file. It is
|
||||
perfectly acceptable for implementations to leave the entity as part
|
||||
of the normal mail stream unless the user requests otherwise. As a
|
||||
consequence, the parameter may be used on any MIME entity, even
|
||||
`inline' ones. These will not normally be written to files, but the
|
||||
parameter could be used to provide a filename if the receiving user
|
||||
should choose to write the part to a file.
|
||||
|
||||
2.4 The Creation-Date parameter
|
||||
|
||||
The creation-date parameter MAY be used to indicate the date at which
|
||||
the file was created. If this parameter is included, the paramter
|
||||
value MUST be a quoted-string which contains a representation of the
|
||||
creation date of the file in [RFC 822] `date-time' format.
|
||||
|
||||
UNIX and POSIX implementors are cautioned that the `st_ctime' file
|
||||
attribute of the `stat' structure is not the creation time of the
|
||||
file; it is thus not appropriate as a source for the creation-date
|
||||
parameter value.
|
||||
|
||||
2.5 The Modification-Date parameter
|
||||
|
||||
The modification-date parameter MAY be used to indicate the date at
|
||||
which the file was last modified. If the modification-date parameter
|
||||
is included, the paramter value MUST be a quoted-string which
|
||||
contains a representation of the last modification date of the file
|
||||
in [RFC 822] `date-time' format.
|
||||
|
||||
2.6 The Read-Date parameter
|
||||
|
||||
The read-date parameter MAY be used to indicate the date at which the
|
||||
file was last read. If the read-date parameter is included, the
|
||||
parameter value MUST be a quoted-string which contains a
|
||||
representation of the last-read date of the file in [RFC 822] `date-
|
||||
time' format.
|
||||
|
||||
2.7 The Size parameter
|
||||
|
||||
The size parameter indicates an approximate size of the file in
|
||||
octets. It can be used, for example, to pre-allocate space before
|
||||
attempting to store the file, or to determine whether enough space
|
||||
exists.
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 5]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
2.8 Future Extensions and Unrecognized Disposition Types
|
||||
|
||||
In the likely event that new parameters or disposition types are
|
||||
needed, they should be registered with the Internet Assigned Numbers
|
||||
Authority (IANA), in the manner specified in Section 9 of this memo.
|
||||
|
||||
Once new disposition types and parameters are defined, there is of
|
||||
course the likelihood that implementations will see disposition types
|
||||
and parameters they do not understand. Furthermore, since x-tokens
|
||||
are allowed, implementations may also see entirely unregistered
|
||||
disposition types and parameters.
|
||||
|
||||
Unrecognized parameters should be ignored. Unrecognized disposition
|
||||
types should be treated as `attachment'. The choice of `attachment'
|
||||
for unrecognized types is made because a sender who goes to the
|
||||
trouble of producing a Content-Disposition header with a new
|
||||
disposition type is more likely aiming for something more elaborate
|
||||
than inline presentation.
|
||||
|
||||
Unless noted otherwise in the definition of a parameter, Content-
|
||||
Disposition parameters are valid for all dispositions. (In contrast
|
||||
to MIME content-type parameters, which are defined on a per-content-
|
||||
type basis.) Thus, for example, the `filename' parameter still means
|
||||
the name of the file to which the part should be written, even if the
|
||||
disposition itself is unrecognized.
|
||||
|
||||
2.9 Content-Disposition and Multipart
|
||||
|
||||
If a Content-Disposition header is used on a multipart body part, it
|
||||
applies to the multipart as a whole, not the individual subparts.
|
||||
The disposition types of the subparts do not need to be consulted
|
||||
until the multipart itself is presented. When the multipart is
|
||||
displayed, then the dispositions of the subparts should be respected.
|
||||
|
||||
If the `inline' disposition is used, the multipart should be
|
||||
displayed as normal; however, an `attachment' subpart should require
|
||||
action from the user to display.
|
||||
|
||||
If the `attachment' disposition is used, presentation of the
|
||||
multipart should not proceed without explicit user action. Once the
|
||||
user has chosen to display the multipart, the individual subpart
|
||||
dispositions should be consulted to determine how to present the
|
||||
subparts.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 6]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
2.10 Content-Disposition and the Main Message
|
||||
|
||||
It is permissible to use Content-Disposition on the main body of an
|
||||
[RFC 822] message.
|
||||
|
||||
3. Examples
|
||||
|
||||
Here is a an example of a body part containing a JPEG image that is
|
||||
intended to be viewed by the user immediately:
|
||||
|
||||
Content-Type: image/jpeg
|
||||
Content-Disposition: inline
|
||||
Content-Description: just a small picture of me
|
||||
|
||||
<jpeg data>
|
||||
|
||||
The following body part contains a JPEG image that should be
|
||||
displayed to the user only if the user requests it. If the JPEG is
|
||||
written to a file, the file should be named "genome.jpg". The
|
||||
recipient's user might also choose to set the last-modified date of
|
||||
the stored file to date in the modification-date parameter:
|
||||
|
||||
Content-Type: image/jpeg
|
||||
Content-Disposition: attachment; filename=genome.jpeg;
|
||||
modification-date="Wed, 12 Feb 1997 16:29:51 -0500";
|
||||
Content-Description: a complete map of the human genome
|
||||
|
||||
<jpeg data>
|
||||
|
||||
The following is an example of the use of the `attachment'
|
||||
disposition with a multipart body part. The user should see text-
|
||||
part-1 immediately, then take some action to view multipart-2. After
|
||||
taking action to view multipart-2, the user will see text-part-2
|
||||
right away, and be required to take action to view jpeg-1. Subparts
|
||||
are indented for clarity; they would not be so indented in a real
|
||||
message.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 7]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
Content-Type: multipart/mixed; boundary=outer
|
||||
Content-Description: multipart-1
|
||||
|
||||
--outer
|
||||
Content-Type: text/plain
|
||||
Content-Disposition: inline
|
||||
Content-Description: text-part-1
|
||||
|
||||
Some text goes here
|
||||
|
||||
--outer
|
||||
Content-Type: multipart/mixed; boundary=inner
|
||||
Content-Disposition: attachment
|
||||
Content-Description: multipart-2
|
||||
|
||||
--inner
|
||||
Content-Type: text/plain
|
||||
Content-Disposition: inline
|
||||
Content-Description: text-part-2
|
||||
|
||||
Some more text here.
|
||||
|
||||
--inner
|
||||
Content-Type: image/jpeg
|
||||
Content-Disposition: attachment
|
||||
Content-Description: jpeg-1
|
||||
|
||||
<jpeg data>
|
||||
--inner--
|
||||
--outer--
|
||||
|
||||
4. Summary
|
||||
|
||||
Content-Disposition takes one of two values, `inline' and
|
||||
`attachment'. `Inline' indicates that the entity should be
|
||||
immediately displayed to the user, whereas `attachment' means that
|
||||
the user should take additional action to view the entity.
|
||||
|
||||
The `filename' parameter can be used to suggest a filename for
|
||||
storing the bodypart, if the user wishes to store it in an external
|
||||
file.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 8]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
There are security issues involved any time users exchange data.
|
||||
While these are not to be minimized, neither does this memo change
|
||||
the status quo in that regard, except in one instance.
|
||||
|
||||
Since this memo provides a way for the sender to suggest a filename,
|
||||
a receiving MUA must take care that the sender's suggested filename
|
||||
does not represent a hazard. Using UNIX as an example, some hazards
|
||||
would be:
|
||||
|
||||
+ Creating startup files (e.g., ".login").
|
||||
|
||||
+ Creating or overwriting system files (e.g., "/etc/passwd").
|
||||
|
||||
+ Overwriting any existing file.
|
||||
|
||||
+ Placing executable files into any command search path
|
||||
(e.g., "~/bin/more").
|
||||
|
||||
+ Sending the file to a pipe (e.g., "| sh").
|
||||
|
||||
In general, the receiving MUA should not name or place the file such
|
||||
that it will get interpreted or executed without the user explicitly
|
||||
initiating the action.
|
||||
|
||||
It is very important to note that this is not an exhaustive list; it
|
||||
is intended as a small set of examples only. Implementors must be
|
||||
alert to the potential hazards on their target systems.
|
||||
|
||||
6. References
|
||||
|
||||
[RFC 2119]
|
||||
Bradner, S., "Key words for use in RFCs to Indicate Requirement
|
||||
Levels", RFC 2119, March 1997.
|
||||
|
||||
[RFC 2184]
|
||||
Freed, N. and K. Moore, "MIME Parameter value and Encoded Words:
|
||||
Character Sets, Lanaguage, and Continuations", RFC 2184, August
|
||||
1997.
|
||||
|
||||
[RFC 2045]
|
||||
Freed, N. and N. Borenstein, "MIME (Multipurpose Internet Mail
|
||||
Extensions) Part One: Format of Internet Message Bodies", RFC
|
||||
2045, December 1996.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 9]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
[RFC 2046]
|
||||
Freed, N. and N. Borenstein, "MIME (Multipurpose Internet Mail
|
||||
Extensions) Part Two: Media Types", RFC 2046, December 1996.
|
||||
|
||||
[RFC 2047]
|
||||
Moore, K., "MIME (Multipurpose Internet Mail Extensions) Part
|
||||
Three: Message Header Extensions for non-ASCII Text", RFC 2047,
|
||||
December 1996.
|
||||
|
||||
[RFC 2048]
|
||||
Freed, N., Klensin, J. and J. Postel, "MIME (Multipurpose
|
||||
Internet Mail Extensions) Part Four: Registration Procedures",
|
||||
RFC 2048, December 1996.
|
||||
|
||||
[RFC 2049]
|
||||
Freed, N. and N. Borenstein, "MIME (Multipurpose Internet Mail
|
||||
Extensions) Part Five: Conformance Criteria and Examples", RFC
|
||||
2049, December 1996.
|
||||
|
||||
[RFC 822]
|
||||
Crocker, D., "Standard for the Format of ARPA Internet Text
|
||||
Messages", STD 11, RFC 822, UDEL, August 1982.
|
||||
|
||||
7. Acknowledgements
|
||||
|
||||
We gratefully acknowledge the help these people provided during the
|
||||
preparation of this draft:
|
||||
|
||||
Nathaniel Borenstein
|
||||
Ned Freed
|
||||
Keith Moore
|
||||
Dave Crocker
|
||||
Dan Pritchett
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 10]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
8. Authors' Addresses
|
||||
|
||||
You should blame the editor of this version of the document for any
|
||||
changes since RFC 1806:
|
||||
|
||||
Keith Moore
|
||||
Department of Computer Science
|
||||
University of Tennessee, Knoxville
|
||||
107 Ayres Hall
|
||||
Knoxville TN 37996-1301
|
||||
USA
|
||||
|
||||
Phone: +1 (423) 974-5067
|
||||
Fax: +1 (423) 974-8296
|
||||
Email: moore@cs.utk.edu
|
||||
|
||||
|
||||
The authors of RFC 1806 are:
|
||||
|
||||
Rens Troost
|
||||
New Century Systems
|
||||
324 East 41st Street #804
|
||||
New York, NY, 10017 USA
|
||||
|
||||
Phone: +1 (212) 557-2050
|
||||
Fax: +1 (212) 557-2049
|
||||
EMail: rens@century.com
|
||||
|
||||
|
||||
Steve Dorner
|
||||
QUALCOMM Incorporated
|
||||
6455 Lusk Boulevard
|
||||
San Diego, CA 92121
|
||||
USA
|
||||
|
||||
EMail: sdorner@qualcomm.com
|
||||
|
||||
|
||||
9. Registration of New Content-Disposition Values and Parameters
|
||||
|
||||
New Content-Disposition values (besides "inline" and "attachment")
|
||||
may be defined only by Internet standards-track documents, or in
|
||||
Experimental documents approved by the Internet Engineering Steering
|
||||
Group.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 11]
|
||||
|
||||
RFC 2183 Content-Disposition August 1997
|
||||
|
||||
|
||||
New content-disposition parameters may be registered by supplying the
|
||||
information in the following template and sending it via electronic
|
||||
mail to IANA@IANA.ORG:
|
||||
|
||||
To: IANA@IANA.ORG
|
||||
Subject: Registration of new Content-Disposition parameter
|
||||
|
||||
Content-Disposition parameter name:
|
||||
|
||||
Allowable values for this parameter:
|
||||
(If the parameter can only assume a small number of values,
|
||||
list each of those values. Otherwise, describe the values
|
||||
that the parameter can assume.)
|
||||
Description:
|
||||
(What is the purpose of this parameter and how is it used?)
|
||||
|
||||
10. Changes since RFC 1806
|
||||
|
||||
The following changes have been made since the earlier version of
|
||||
this document, published in RFC 1806 as an Experimental protocol:
|
||||
|
||||
+ Updated references to MIME documents. In some cases this
|
||||
involved substituting a reference to one of the current MIME
|
||||
RFCs for a reference to RFC 1521; in other cases, a reference to
|
||||
RFC 1521 was simply replaced with the word "MIME".
|
||||
|
||||
+ Added a section on registration procedures, since none of the
|
||||
procedures in RFC 2048 seemed to be appropriate.
|
||||
|
||||
+ Added new parameter types: creation-date, modification-date,
|
||||
read-date, and size.
|
||||
|
||||
|
||||
+ Incorporated a reference to draft-freed-pvcsc-* for encoding
|
||||
long or non-ASCII parameter values.
|
||||
|
||||
+ Added reference to RFC 2119 to define MUST, SHOULD, etc.
|
||||
keywords.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Troost, et. al. Standards Track [Page 12]
|
||||
|
|
@ -0,0 +1,899 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group J. Myers
|
||||
Request for Comments: 2222 Netscape Communications
|
||||
Category: Standards Track October 1997
|
||||
|
||||
|
||||
Simple Authentication and Security Layer (SASL)
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (1997). All Rights Reserved.
|
||||
|
||||
Table of Contents
|
||||
|
||||
1. Abstract .............................................. 2
|
||||
2. Organization of this Document ......................... 2
|
||||
2.1. How to Read This Document ............................. 2
|
||||
2.2. Conventions Used in this Document ..................... 2
|
||||
2.3. Examples .............................................. 3
|
||||
3. Introduction and Overview ............................. 3
|
||||
4. Profiling requirements ................................ 4
|
||||
5. Specific issues ....................................... 5
|
||||
5.1. Client sends data first ............................... 5
|
||||
5.2. Server returns success with additional data ........... 5
|
||||
5.3. Multiple authentications .............................. 5
|
||||
6. Registration procedures ............................... 6
|
||||
6.1. Comments on SASL mechanism registrations .............. 6
|
||||
6.2. Location of Registered SASL Mechanism List ............ 6
|
||||
6.3. Change Control ........................................ 7
|
||||
6.4. Registration Template ................................. 7
|
||||
7. Mechanism definitions ................................. 8
|
||||
7.1. Kerberos version 4 mechanism .......................... 8
|
||||
7.2. GSSAPI mechanism ...................................... 9
|
||||
7.2.1 Client side of authentication protocol exchange ....... 9
|
||||
7.2.2 Server side of authentication protocol exchange ....... 10
|
||||
7.2.3 Security layer ........................................ 11
|
||||
7.3. S/Key mechanism ....................................... 11
|
||||
7.4. External mechanism .................................... 12
|
||||
8. References ............................................ 13
|
||||
9. Security Considerations ............................... 13
|
||||
10. Author's Address ...................................... 14
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 1]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
Appendix A. Relation of SASL to Transport Security .......... 15
|
||||
Full Copyright Statement .................................... 16
|
||||
|
||||
1. Abstract
|
||||
|
||||
This document describes a method for adding authentication support to
|
||||
connection-based protocols. To use this specification, a protocol
|
||||
includes a command for identifying and authenticating a user to a
|
||||
server and for optionally negotiating protection of subsequent
|
||||
protocol interactions. If its use is negotiated, a security layer is
|
||||
inserted between the protocol and the connection. This document
|
||||
describes how a protocol specifies such a command, defines several
|
||||
mechanisms for use by the command, and defines the protocol used for
|
||||
carrying a negotiated security layer over the connection.
|
||||
|
||||
2. Organization of this Document
|
||||
|
||||
2.1. How to Read This Document
|
||||
|
||||
This document is written to serve two different audiences, protocol
|
||||
designers using this specification to support authentication in their
|
||||
protocol, and implementors of clients or servers for those protocols
|
||||
using this specification.
|
||||
|
||||
The sections "Introduction and Overview", "Profiling requirements",
|
||||
and "Security Considerations" cover issues that protocol designers
|
||||
need to understand and address in profiling this specification for
|
||||
use in a specific protocol.
|
||||
|
||||
Implementors of a protocol using this specification need the
|
||||
protocol-specific profiling information in addition to the
|
||||
information in this document.
|
||||
|
||||
2.2. Conventions Used in this Document
|
||||
|
||||
In examples, "C:" and "S:" indicate lines sent by the client and
|
||||
server respectively.
|
||||
|
||||
The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
|
||||
in this document are to be interpreted as defined in "Key words for
|
||||
use in RFCs to Indicate Requirement Levels" [RFC 2119].
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 2]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
2.3. Examples
|
||||
|
||||
Examples in this document are for the IMAP profile [RFC 2060] of this
|
||||
specification. The base64 encoding of challenges and responses, as
|
||||
well as the "+ " preceding the responses are part of the IMAP4
|
||||
profile, not part of the SASL specification itself.
|
||||
|
||||
3. Introduction and Overview
|
||||
|
||||
The Simple Authentication and Security Layer (SASL) is a method for
|
||||
adding authentication support to connection-based protocols. To use
|
||||
this specification, a protocol includes a command for identifying and
|
||||
authenticating a user to a server and for optionally negotiating a
|
||||
security layer for subsequent protocol interactions.
|
||||
|
||||
The command has a required argument identifying a SASL mechanism.
|
||||
SASL mechanisms are named by strings, from 1 to 20 characters in
|
||||
length, consisting of upper-case letters, digits, hyphens, and/or
|
||||
underscores. SASL mechanism names must be registered with the IANA.
|
||||
Procedures for registering new SASL mechanisms are given in the
|
||||
section "Registration procedures"
|
||||
|
||||
If a server supports the requested mechanism, it initiates an
|
||||
authentication protocol exchange. This consists of a series of
|
||||
server challenges and client responses that are specific to the
|
||||
requested mechanism. The challenges and responses are defined by the
|
||||
mechanisms as binary tokens of arbitrary length. The protocol's
|
||||
profile then specifies how these binary tokens are then encoded for
|
||||
transfer over the connection.
|
||||
|
||||
After receiving the authentication command or any client response, a
|
||||
server may issue a challenge, indicate failure, or indicate
|
||||
completion. The protocol's profile specifies how the server
|
||||
indicates which of the above it is doing.
|
||||
|
||||
After receiving a challenge, a client may issue a response or abort
|
||||
the exchange. The protocol's profile specifies how the client
|
||||
indicates which of the above it is doing.
|
||||
|
||||
During the authentication protocol exchange, the mechanism performs
|
||||
authentication, transmits an authorization identity (frequently known
|
||||
as a userid) from the client to server, and negotiates the use of a
|
||||
mechanism-specific security layer. If the use of a security layer is
|
||||
agreed upon, then the mechanism must also define or negotiate the
|
||||
maximum cipher-text buffer size that each side is able to receive.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 3]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
The transmitted authorization identity may be different than the
|
||||
identity in the client's authentication credentials. This permits
|
||||
agents such as proxy servers to authenticate using their own
|
||||
credentials, yet request the access privileges of the identity for
|
||||
which they are proxying. With any mechanism, transmitting an
|
||||
authorization identity of the empty string directs the server to
|
||||
derive an authorization identity from the client's authentication
|
||||
credentials.
|
||||
|
||||
If use of a security layer is negotiated, it is applied to all
|
||||
subsequent data sent over the connection. The security layer takes
|
||||
effect immediately following the last response of the authentication
|
||||
exchange for data sent by the client and the completion indication
|
||||
for data sent by the server. Once the security layer is in effect,
|
||||
the protocol stream is processed by the security layer into buffers
|
||||
of cipher-text. Each buffer is transferred over the connection as a
|
||||
stream of octets prepended with a four octet field in network byte
|
||||
order that represents the length of the following buffer. The length
|
||||
of the cipher-text buffer must be no larger than the maximum size
|
||||
that was defined or negotiated by the other side.
|
||||
|
||||
4. Profiling requirements
|
||||
|
||||
In order to use this specification, a protocol definition must supply
|
||||
the following information:
|
||||
|
||||
1. A service name, to be selected from the IANA registry of "service"
|
||||
elements for the GSSAPI host-based service name form [RFC 2078].
|
||||
|
||||
2. A definition of the command to initiate the authentication
|
||||
protocol exchange. This command must have as a parameter the
|
||||
mechanism name being selected by the client.
|
||||
|
||||
The command SHOULD have an optional parameter giving an initial
|
||||
response. This optional parameter allows the client to avoid a
|
||||
round trip when using a mechanism which is defined to have the
|
||||
client send data first. When this initial response is sent by the
|
||||
client and the selected mechanism is defined to have the server
|
||||
start with an initial challenge, the command fails. See section
|
||||
5.1 of this document for further information.
|
||||
|
||||
3. A definition of the method by which the authentication protocol
|
||||
exchange is carried out, including how the challenges and
|
||||
responses are encoded, how the server indicates completion or
|
||||
failure of the exchange, how the client aborts an exchange, and
|
||||
how the exchange method interacts with any line length limits in
|
||||
the protocol.
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 4]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
4. Identification of the octet where any negotiated security layer
|
||||
starts to take effect, in both directions.
|
||||
|
||||
5. A specification of how the authorization identity passed from the
|
||||
client to the server is to be interpreted.
|
||||
|
||||
5. Specific issues
|
||||
|
||||
5.1. Client sends data first
|
||||
|
||||
Some mechanisms specify that the first data sent in the
|
||||
authentication protocol exchange is from the client to the server.
|
||||
|
||||
If a protocol's profile permits the command which initiates an
|
||||
authentication protocol exchange to contain an initial client
|
||||
response, this parameter SHOULD be used with such mechanisms.
|
||||
|
||||
If the initial client response parameter is not given, or if a
|
||||
protocol's profile does not permit the command which initiates an
|
||||
authentication protocol exchange to contain an initial client
|
||||
response, then the server issues a challenge with no data. The
|
||||
client's response to this challenge is then used as the initial
|
||||
client response. (The server then proceeds to send the next
|
||||
challenge, indicates completion, or indicates failure.)
|
||||
|
||||
5.2. Server returns success with additional data
|
||||
|
||||
Some mechanisms may specify that server challenge data be sent to the
|
||||
client along with an indication of successful completion of the
|
||||
exchange. This data would, for example, authenticate the server to
|
||||
the client.
|
||||
|
||||
If a protocol's profile does not permit this server challenge to be
|
||||
returned with a success indication, then the server issues the server
|
||||
challenge without an indication of successful completion. The client
|
||||
then responds with no data. After receiving this empty response, the
|
||||
server then indicates successful completion.
|
||||
|
||||
5.3. Multiple authentications
|
||||
|
||||
Unless otherwise stated by the protocol's profile, only one
|
||||
successful SASL negotiation may occur in a protocol session. In this
|
||||
case, once an authentication protocol exchange has successfully
|
||||
completed, further attempts to initiate an authentication protocol
|
||||
exchange fail.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 5]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
In the case that a profile explicitly permits multiple successful
|
||||
SASL negotiations to occur, then in no case may multiple security
|
||||
layers be simultaneously in effect. If a security layer is in effect
|
||||
and a subsequent SASL negotiation selects no security layer, the
|
||||
original security layer remains in effect. If a security layer is in
|
||||
effect and a subsequent SASL negotiation selects a second security
|
||||
layer, then the second security layer replaces the first.
|
||||
|
||||
6. Registration procedures
|
||||
|
||||
Registration of a SASL mechanism is done by filling in the template
|
||||
in section 6.4 and sending it in to iana@isi.edu. IANA has the right
|
||||
to reject obviously bogus registrations, but will perform no review
|
||||
of clams made in the registration form.
|
||||
|
||||
There is no naming convention for SASL mechanisms; any name that
|
||||
conforms to the syntax of a SASL mechanism name can be registered.
|
||||
|
||||
While the registration procedures do not require it, authors of SASL
|
||||
mechanisms are encouraged to seek community review and comment
|
||||
whenever that is feasible. Authors may seek community review by
|
||||
posting a specification of their proposed mechanism as an internet-
|
||||
draft. SASL mechanisms intended for widespread use should be
|
||||
standardized through the normal IETF process, when appropriate.
|
||||
|
||||
6.1. Comments on SASL mechanism registrations
|
||||
|
||||
Comments on registered SASL mechanisms should first be sent to the
|
||||
"owner" of the mechanism. Submitters of comments may, after a
|
||||
reasonable attempt to contact the owner, request IANA to attach their
|
||||
comment to the SASL mechanism registration itself. If IANA approves
|
||||
of this the comment will be made accessible in conjunction with the
|
||||
SASL mechanism registration itself.
|
||||
|
||||
6.2. Location of Registered SASL Mechanism List
|
||||
|
||||
SASL mechanism registrations will be posted in the anonymous FTP
|
||||
directory "ftp://ftp.isi.edu/in-notes/iana/assignments/sasl-
|
||||
mechanisms/" and all registered SASL mechanisms will be listed in the
|
||||
periodically issued "Assigned Numbers" RFC [currently STD 2, RFC
|
||||
1700]. The SASL mechanism description and other supporting material
|
||||
may also be published as an Informational RFC by sending it to "rfc-
|
||||
editor@isi.edu" (please follow the instructions to RFC authors [RFC
|
||||
2223]).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 6]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
6.3. Change Control
|
||||
|
||||
Once a SASL mechanism registration has been published by IANA, the
|
||||
author may request a change to its definition. The change request
|
||||
follows the same procedure as the registration request.
|
||||
|
||||
The owner of a SASL mechanism may pass responsibility for the SASL
|
||||
mechanism to another person or agency by informing IANA; this can be
|
||||
done without discussion or review.
|
||||
|
||||
The IESG may reassign responsibility for a SASL mechanism. The most
|
||||
common case of this will be to enable changes to be made to
|
||||
mechanisms where the author of the registration has died, moved out
|
||||
of contact or is otherwise unable to make changes that are important
|
||||
to the community.
|
||||
|
||||
SASL mechanism registrations may not be deleted; mechanisms which are
|
||||
no longer believed appropriate for use can be declared OBSOLETE by a
|
||||
change to their "intended use" field; such SASL mechanisms will be
|
||||
clearly marked in the lists published by IANA.
|
||||
|
||||
The IESG is considered to be the owner of all SASL mechanisms which
|
||||
are on the IETF standards track.
|
||||
|
||||
6.4. Registration Template
|
||||
|
||||
To: iana@iana.org
|
||||
Subject: Registration of SASL mechanism X
|
||||
|
||||
SASL mechanism name:
|
||||
|
||||
Security considerations:
|
||||
|
||||
Published specification (optional, recommended):
|
||||
|
||||
Person & email address to contact for further information:
|
||||
|
||||
Intended usage:
|
||||
|
||||
(One of COMMON, LIMITED USE or OBSOLETE)
|
||||
|
||||
Author/Change controller:
|
||||
|
||||
(Any other information that the author deems interesting may be
|
||||
added below this line.)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 7]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
7. Mechanism definitions
|
||||
|
||||
The following mechanisms are hereby defined.
|
||||
|
||||
7.1. Kerberos version 4 mechanism
|
||||
|
||||
The mechanism name associated with Kerberos version 4 is
|
||||
"KERBEROS_V4".
|
||||
|
||||
The first challenge consists of a random 32-bit number in network
|
||||
byte order. The client responds with a Kerberos ticket and an
|
||||
authenticator for the principal "service.hostname@realm", where
|
||||
"service" is the service name specified in the protocol's profile,
|
||||
"hostname" is the first component of the host name of the server with
|
||||
all letters in lower case, and where "realm" is the Kerberos realm of
|
||||
the server. The encrypted checksum field included within the
|
||||
Kerberos authenticator contains the server provided challenge in
|
||||
network byte order.
|
||||
|
||||
Upon decrypting and verifying the ticket and authenticator, the
|
||||
server verifies that the contained checksum field equals the original
|
||||
server provided random 32-bit number. Should the verification be
|
||||
successful, the server must add one to the checksum and construct 8
|
||||
octets of data, with the first four octets containing the incremented
|
||||
checksum in network byte order, the fifth octet containing a bit-mask
|
||||
specifying the security layers supported by the server, and the sixth
|
||||
through eighth octets containing, in network byte order, the maximum
|
||||
cipher-text buffer size the server is able to receive. The server
|
||||
must encrypt using DES ECB mode the 8 octets of data in the session
|
||||
key and issue that encrypted data in a second challenge. The client
|
||||
considers the server authenticated if the first four octets of the
|
||||
un-encrypted data is equal to one plus the checksum it previously
|
||||
sent.
|
||||
|
||||
The client must construct data with the first four octets containing
|
||||
the original server-issued checksum in network byte order, the fifth
|
||||
octet containing the bit-mask specifying the selected security layer,
|
||||
the sixth through eighth octets containing in network byte order the
|
||||
maximum cipher-text buffer size the client is able to receive, and
|
||||
the following octets containing the authorization identity. The
|
||||
client must then append from one to eight zero-valued octets so that
|
||||
the length of the data is a multiple of eight octets. The client must
|
||||
then encrypt using DES PCBC mode the data with the session key and
|
||||
respond with the encrypted data. The server decrypts the data and
|
||||
verifies the contained checksum. The server must verify that the
|
||||
principal identified in the Kerberos ticket is authorized to connect
|
||||
as that authorization identity. After this verification, the
|
||||
authentication process is complete.
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 8]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
The security layers and their corresponding bit-masks are as follows:
|
||||
|
||||
1 No security layer
|
||||
2 Integrity (krb_mk_safe) protection
|
||||
4 Privacy (krb_mk_priv) protection
|
||||
|
||||
Other bit-masks may be defined in the future; bits which are not
|
||||
understood must be negotiated off.
|
||||
|
||||
EXAMPLE: The following are two Kerberos version 4 login scenarios to
|
||||
the IMAP4 protocol (note that the line breaks in the sample
|
||||
authenticators are for editorial clarity and are not in real
|
||||
authenticators)
|
||||
|
||||
S: * OK IMAP4 Server
|
||||
C: A001 AUTHENTICATE KERBEROS_V4
|
||||
S: + AmFYig==
|
||||
C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT
|
||||
+nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd
|
||||
WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh
|
||||
S: + or//EoAADZI=
|
||||
C: DiAF5A4gA+oOIALuBkAAmw==
|
||||
S: A001 OK Kerberos V4 authentication successful
|
||||
|
||||
|
||||
S: * OK IMAP4 Server
|
||||
C: A001 AUTHENTICATE KERBEROS_V4
|
||||
S: + gcfgCA==
|
||||
C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT
|
||||
+nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd
|
||||
WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh
|
||||
S: A001 NO Kerberos V4 authentication failed
|
||||
|
||||
7.2. GSSAPI mechanism
|
||||
|
||||
The mechanism name associated with all mechanisms employing the
|
||||
GSSAPI [RFC 2078] is "GSSAPI".
|
||||
|
||||
7.2.1 Client side of authentication protocol exchange
|
||||
|
||||
The client calls GSS_Init_sec_context, passing in 0 for
|
||||
input_context_handle (initially) and a targ_name equal to output_name
|
||||
from GSS_Import_Name called with input_name_type of
|
||||
GSS_C_NT_HOSTBASED_SERVICE and input_name_string of
|
||||
"service@hostname" where "service" is the service name specified in
|
||||
the protocol's profile, and "hostname" is the fully qualified host
|
||||
name of the server. The client then responds with the resulting
|
||||
output_token. If GSS_Init_sec_context returns GSS_S_CONTINUE_NEEDED,
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 9]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
then the client should expect the server to issue a token in a
|
||||
subsequent challenge. The client must pass the token to another call
|
||||
to GSS_Init_sec_context, repeating the actions in this paragraph.
|
||||
|
||||
When GSS_Init_sec_context returns GSS_S_COMPLETE, the client takes
|
||||
the following actions: If the last call to GSS_Init_sec_context
|
||||
returned an output_token, then the client responds with the
|
||||
output_token, otherwise the client responds with no data. The client
|
||||
should then expect the server to issue a token in a subsequent
|
||||
challenge. The client passes this token to GSS_Unwrap and interprets
|
||||
the first octet of resulting cleartext as a bit-mask specifying the
|
||||
security layers supported by the server and the second through fourth
|
||||
octets as the maximum size output_message to send to the server. The
|
||||
client then constructs data, with the first octet containing the
|
||||
bit-mask specifying the selected security layer, the second through
|
||||
fourth octets containing in network byte order the maximum size
|
||||
output_message the client is able to receive, and the remaining
|
||||
octets containing the authorization identity. The client passes the
|
||||
data to GSS_Wrap with conf_flag set to FALSE, and responds with the
|
||||
generated output_message. The client can then consider the server
|
||||
authenticated.
|
||||
|
||||
7.2.2 Server side of authentication protocol exchange
|
||||
|
||||
The server passes the initial client response to
|
||||
GSS_Accept_sec_context as input_token, setting input_context_handle
|
||||
to 0 (initially). If GSS_Accept_sec_context returns
|
||||
GSS_S_CONTINUE_NEEDED, the server returns the generated output_token
|
||||
to the client in challenge and passes the resulting response to
|
||||
another call to GSS_Accept_sec_context, repeating the actions in this
|
||||
paragraph.
|
||||
|
||||
When GSS_Accept_sec_context returns GSS_S_COMPLETE, the client takes
|
||||
the following actions: If the last call to GSS_Accept_sec_context
|
||||
returned an output_token, the server returns it to the client in a
|
||||
challenge and expects a reply from the client with no data. Whether
|
||||
or not an output_token was returned (and after receipt of any
|
||||
response from the client to such an output_token), the server then
|
||||
constructs 4 octets of data, with the first octet containing a bit-
|
||||
mask specifying the security layers supported by the server and the
|
||||
second through fourth octets containing in network byte order the
|
||||
maximum size output_token the server is able to receive. The server
|
||||
must then pass the plaintext to GSS_Wrap with conf_flag set to FALSE
|
||||
and issue the generated output_message to the client in a challenge.
|
||||
The server must then pass the resulting response to GSS_Unwrap and
|
||||
interpret the first octet of resulting cleartext as the bit-mask for
|
||||
the selected security layer, the second through fourth octets as the
|
||||
maximum size output_message to send to the client, and the remaining
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 10]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
octets as the authorization identity. The server must verify that
|
||||
the src_name is authorized to authenticate as the authorization
|
||||
identity. After these verifications, the authentication process is
|
||||
complete.
|
||||
|
||||
7.2.3 Security layer
|
||||
|
||||
The security layers and their corresponding bit-masks are as follows:
|
||||
|
||||
1 No security layer
|
||||
2 Integrity protection.
|
||||
Sender calls GSS_Wrap with conf_flag set to FALSE
|
||||
4 Privacy protection.
|
||||
Sender calls GSS_Wrap with conf_flag set to TRUE
|
||||
|
||||
Other bit-masks may be defined in the future; bits which are not
|
||||
understood must be negotiated off.
|
||||
|
||||
7.3. S/Key mechanism
|
||||
|
||||
The mechanism name associated with S/Key [RFC 1760] using the MD4
|
||||
digest algorithm is "SKEY".
|
||||
|
||||
The client sends an initial response with the authorization identity.
|
||||
|
||||
The server then issues a challenge which contains the decimal
|
||||
sequence number followed by a single space and the seed string for
|
||||
the indicated authorization identity. The client responds with the
|
||||
one-time-password, as either a 64-bit value in network byte order or
|
||||
encoded in the "six English words" format.
|
||||
|
||||
The server must verify the one-time-password. After this
|
||||
verification, the authentication process is complete.
|
||||
|
||||
S/Key authentication does not provide for any security layers.
|
||||
|
||||
EXAMPLE: The following are two S/Key login scenarios in the IMAP4
|
||||
protocol.
|
||||
|
||||
S: * OK IMAP4 Server
|
||||
C: A001 AUTHENTICATE SKEY
|
||||
S: +
|
||||
C: bW9yZ2Fu
|
||||
S: + OTUgUWE1ODMwOA==
|
||||
C: Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
|
||||
S: A001 OK S/Key authentication successful
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 11]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
S: * OK IMAP4 Server
|
||||
C: A001 AUTHENTICATE SKEY
|
||||
S: +
|
||||
C: c21pdGg=
|
||||
S: + OTUgUWE1ODMwOA==
|
||||
C: BsAY3g4gBNo=
|
||||
S: A001 NO S/Key authentication failed
|
||||
|
||||
The following is an S/Key login scenario in an IMAP4-like protocol
|
||||
which has an optional "initial response" argument to the AUTHENTICATE
|
||||
command.
|
||||
|
||||
S: * OK IMAP4-Like Server
|
||||
C: A001 AUTHENTICATE SKEY bW9yZ2Fu
|
||||
S: + OTUgUWE1ODMwOA==
|
||||
C: Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA==
|
||||
S: A001 OK S/Key authentication successful
|
||||
|
||||
7.4. External mechanism
|
||||
|
||||
The mechanism name associated with external authentication is
|
||||
"EXTERNAL".
|
||||
|
||||
The client sends an initial response with the authorization identity.
|
||||
|
||||
The server uses information, external to SASL, to determine whether
|
||||
the client is authorized to authenticate as the authorization
|
||||
identity. If the client is so authorized, the server indicates
|
||||
successful completion of the authentication exchange; otherwise the
|
||||
server indicates failure.
|
||||
|
||||
The system providing this external information may be, for example,
|
||||
IPsec or TLS.
|
||||
|
||||
If the client sends the empty string as the authorization identity
|
||||
(thus requesting the authorization identity be derived from the
|
||||
client's authentication credentials), the authorization identity is
|
||||
to be derived from authentication credentials which exist in the
|
||||
system which is providing the external authentication.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 12]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
8. References
|
||||
|
||||
[RFC 2060] Crispin, M., "Internet Message Access Protocol - Version
|
||||
4rev1", RFC 2060, December 1996.
|
||||
|
||||
[RFC 2078] Linn, J., "Generic Security Service Application Program
|
||||
Interface, Version 2", RFC 2078, January 1997.
|
||||
|
||||
[RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", RFC 2119, March 1997.
|
||||
|
||||
[RFC 2223] Postel, J., and J. Reynolds, "Instructions to RFC
|
||||
Authors", RFC 2223, October 1997.
|
||||
|
||||
[RFC 1760] Haller, N., "The S/Key One-Time Password System", RFC
|
||||
1760, February 1995.
|
||||
|
||||
[RFC 1700] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2,
|
||||
RFC 1700, October 1994.
|
||||
|
||||
9. Security Considerations
|
||||
|
||||
Security issues are discussed throughout this memo.
|
||||
|
||||
The mechanisms that support integrity protection are designed such
|
||||
that the negotiation of the security layer and authorization identity
|
||||
is integrity protected. When the client selects a security layer
|
||||
with at least integrity protection, this protects against an active
|
||||
attacker hijacking the connection and modifying the authentication
|
||||
exchange to negotiate a plaintext connection.
|
||||
|
||||
When a server or client supports multiple authentication mechanisms,
|
||||
each of which has a different security strength, it is possible for
|
||||
an active attacker to cause a party to use the least secure mechanism
|
||||
supported. To protect against this sort of attack, a client or
|
||||
server which supports mechanisms of different strengths should have a
|
||||
configurable minimum strength that it will use. It is not sufficient
|
||||
for this minimum strength check to only be on the server, since an
|
||||
active attacker can change which mechanisms the client sees as being
|
||||
supported, causing the client to send authentication credentials for
|
||||
its weakest supported mechanism.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 13]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
The client's selection of a SASL mechanism is done in the clear and
|
||||
may be modified by an active attacker. It is important for any new
|
||||
SASL mechanisms to be designed such that an active attacker cannot
|
||||
obtain an authentication with weaker security properties by modifying
|
||||
the SASL mechanism name and/or the challenges and responses.
|
||||
|
||||
Any protocol interactions prior to authentication are performed in
|
||||
the clear and may be modified by an active attacker. In the case
|
||||
where a client selects integrity protection, it is important that any
|
||||
security-sensitive protocol negotiations be performed after
|
||||
authentication is complete. Protocols should be designed such that
|
||||
negotiations performed prior to authentication should be either
|
||||
ignored or revalidated once authentication is complete.
|
||||
|
||||
10. Author's Address
|
||||
|
||||
John G. Myers
|
||||
Netscape Communications
|
||||
501 E. Middlefield Road
|
||||
Mail Stop MV-029
|
||||
Mountain View, CA 94043-4042
|
||||
|
||||
EMail: jgmyers@netscape.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 14]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
Appendix A. Relation of SASL to Transport Security
|
||||
|
||||
Questions have been raised about the relationship between SASL and
|
||||
various services (such as IPsec and TLS) which provide a secured
|
||||
connection.
|
||||
|
||||
Two of the key features of SASL are:
|
||||
|
||||
1. The separation of the authorization identity from the identity in
|
||||
the client's credentials. This permits agents such as proxy
|
||||
servers to authenticate using their own credentials, yet request
|
||||
the access privileges of the identity for which they are proxying.
|
||||
|
||||
2. Upon successful completion of an authentication exchange, the
|
||||
server knows the authorization identity the client wishes to use.
|
||||
This allows servers to move to a "user is authenticated" state in
|
||||
the protocol.
|
||||
|
||||
These features are extremely important to some application protocols,
|
||||
yet Transport Security services do not always provide them. To
|
||||
define SASL mechanisms based on these services would be a very messy
|
||||
task, as the framing of these services would be redundant with the
|
||||
framing of SASL and some method of providing these important SASL
|
||||
features would have to be devised.
|
||||
|
||||
Sometimes it is desired to enable within an existing connection the
|
||||
use of a security service which does not fit the SASL model. (TLS is
|
||||
an example of such a service.) This can be done by adding a command,
|
||||
for example "STARTTLS", to the protocol. Such a command is outside
|
||||
the scope of SASL, and should be different from the command which
|
||||
starts a SASL authentication protocol exchange.
|
||||
|
||||
In certain situations, it is reasonable to use SASL underneath one of
|
||||
these Transport Security services. The transport service would
|
||||
secure the connection, either service would authenticate the client,
|
||||
and SASL would negotiate the authorization identity. The SASL
|
||||
negotiation would be what moves the protocol from "unauthenticated"
|
||||
to "authenticated" state. The "EXTERNAL" SASL mechanism is
|
||||
explicitly intended to handle the case where the transport service
|
||||
secures the connection and authenticates the client and SASL
|
||||
negotiates the authorization identity.
|
||||
|
||||
When using SASL underneath a sufficiently strong Transport Security
|
||||
service, a SASL security layer would most likely be redundant. The
|
||||
client and server would thus probably want to negotiate off the use
|
||||
of a SASL security layer.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 15]
|
||||
|
||||
RFC 2222 SASL October 1997
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (1997). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implmentation may be prepared, copied, published
|
||||
andand distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 16]
|
||||
|
|
@ -0,0 +1,563 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group N. Freed
|
||||
Request for Comments: 2231 Innosoft
|
||||
Updates: 2045, 2047, 2183 K. Moore
|
||||
Obsoletes: 2184 University of Tennessee
|
||||
Category: Standards Track November 1997
|
||||
|
||||
|
||||
MIME Parameter Value and Encoded Word Extensions:
|
||||
Character Sets, Languages, and Continuations
|
||||
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (1997). All Rights Reserved.
|
||||
|
||||
1. Abstract
|
||||
|
||||
This memo defines extensions to the RFC 2045 media type and RFC 2183
|
||||
disposition parameter value mechanisms to provide
|
||||
|
||||
(1) a means to specify parameter values in character sets
|
||||
other than US-ASCII,
|
||||
|
||||
(2) to specify the language to be used should the value be
|
||||
displayed, and
|
||||
|
||||
(3) a continuation mechanism for long parameter values to
|
||||
avoid problems with header line wrapping.
|
||||
|
||||
This memo also defines an extension to the encoded words defined in
|
||||
RFC 2047 to allow the specification of the language to be used for
|
||||
display as well as the character set.
|
||||
|
||||
2. Introduction
|
||||
|
||||
The Multipurpose Internet Mail Extensions, or MIME [RFC-2045, RFC-
|
||||
2046, RFC-2047, RFC-2048, RFC-2049], define a message format that
|
||||
allows for:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 1]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
(1) textual message bodies in character sets other than
|
||||
US-ASCII,
|
||||
|
||||
(2) non-textual message bodies,
|
||||
|
||||
(3) multi-part message bodies, and
|
||||
|
||||
(4) textual header information in character sets other than
|
||||
US-ASCII.
|
||||
|
||||
MIME is now widely deployed and is used by a variety of Internet
|
||||
protocols, including, of course, Internet email. However, MIME's
|
||||
success has resulted in the need for additional mechanisms that were
|
||||
not provided in the original protocol specification.
|
||||
|
||||
In particular, existing MIME mechanisms provide for named media type
|
||||
(content-type field) parameters as well as named disposition
|
||||
(content-disposition field). A MIME media type may specify any
|
||||
number of parameters associated with all of its subtypes, and any
|
||||
specific subtype may specify additional parameters for its own use. A
|
||||
MIME disposition value may specify any number of associated
|
||||
parameters, the most important of which is probably the attachment
|
||||
disposition's filename parameter.
|
||||
|
||||
These parameter names and values end up appearing in the content-type
|
||||
and content-disposition header fields in Internet email. This
|
||||
inherently imposes three crucial limitations:
|
||||
|
||||
(1) Lines in Internet email header fields are folded
|
||||
according to RFC 822 folding rules. This makes long
|
||||
parameter values problematic.
|
||||
|
||||
(2) MIME headers, like the RFC 822 headers they often
|
||||
appear in, are limited to 7bit US-ASCII, and the
|
||||
encoded-word mechanisms of RFC 2047 are not available
|
||||
to parameter values. This makes it impossible to have
|
||||
parameter values in character sets other than US-ASCII
|
||||
without specifying some sort of private per-parameter
|
||||
encoding.
|
||||
|
||||
(3) It has recently become clear that character set
|
||||
information is not sufficient to properly display some
|
||||
sorts of information -- language information is also
|
||||
needed [RFC-2130]. For example, support for
|
||||
handicapped users may require reading text string
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 2]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
aloud. The language the text is written in is needed
|
||||
for this to be done correctly. Some parameter values
|
||||
may need to be displayed, hence there is a need to
|
||||
allow for the inclusion of language information.
|
||||
|
||||
The last problem on this list is also an issue for the encoded words
|
||||
defined by RFC 2047, as encoded words are intended primarily for
|
||||
display purposes.
|
||||
|
||||
This document defines extensions that address all of these
|
||||
limitations. All of these extensions are implemented in a fashion
|
||||
that is completely compatible at a syntactic level with existing MIME
|
||||
implementations. In addition, the extensions are designed to have as
|
||||
little impact as possible on existing uses of MIME.
|
||||
|
||||
IMPORTANT NOTE: These mechanisms end up being somewhat gibbous when
|
||||
they actually are used. As such, these mechanisms should not be used
|
||||
lightly; they should be reserved for situations where a real need for
|
||||
them exists.
|
||||
|
||||
2.1. Requirements notation
|
||||
|
||||
This document occasionally uses terms that appear in capital letters.
|
||||
When the terms "MUST", "SHOULD", "MUST NOT", "SHOULD NOT", and "MAY"
|
||||
appear capitalized, they are being used to indicate particular
|
||||
requirements of this specification. A discussion of the meanings of
|
||||
these terms appears in [RFC- 2119].
|
||||
|
||||
3. Parameter Value Continuations
|
||||
|
||||
Long MIME media type or disposition parameter values do not interact
|
||||
well with header line wrapping conventions. In particular, proper
|
||||
header line wrapping depends on there being places where linear
|
||||
whitespace (LWSP) is allowed, which may or may not be present in a
|
||||
parameter value, and even if present may not be recognizable as such
|
||||
since specific knowledge of parameter value syntax may not be
|
||||
available to the agent doing the line wrapping. The result is that
|
||||
long parameter values may end up getting truncated or otherwise
|
||||
damaged by incorrect line wrapping implementations.
|
||||
|
||||
A mechanism is therefore needed to break up parameter values into
|
||||
smaller units that are amenable to line wrapping. Any such mechanism
|
||||
MUST be compatible with existing MIME processors. This means that
|
||||
|
||||
(1) the mechanism MUST NOT change the syntax of MIME media
|
||||
type and disposition lines, and
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 3]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
(2) the mechanism MUST NOT depend on parameter ordering
|
||||
since MIME states that parameters are not order
|
||||
sensitive. Note that while MIME does prohibit
|
||||
modification of MIME headers during transport, it is
|
||||
still possible that parameters will be reordered when
|
||||
user agent level processing is done.
|
||||
|
||||
The obvious solution, then, is to use multiple parameters to contain
|
||||
a single parameter value and to use some kind of distinguished name
|
||||
to indicate when this is being done. And this obvious solution is
|
||||
exactly what is specified here: The asterisk character ("*") followed
|
||||
by a decimal count is employed to indicate that multiple parameters
|
||||
are being used to encapsulate a single parameter value. The count
|
||||
starts at 0 and increments by 1 for each subsequent section of the
|
||||
parameter value. Decimal values are used and neither leading zeroes
|
||||
nor gaps in the sequence are allowed.
|
||||
|
||||
The original parameter value is recovered by concatenating the
|
||||
various sections of the parameter, in order. For example, the
|
||||
content-type field
|
||||
|
||||
Content-Type: message/external-body; access-type=URL;
|
||||
URL*0="ftp://";
|
||||
URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"
|
||||
|
||||
is semantically identical to
|
||||
|
||||
Content-Type: message/external-body; access-type=URL;
|
||||
URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"
|
||||
|
||||
Note that quotes around parameter values are part of the value
|
||||
syntax; they are NOT part of the value itself. Furthermore, it is
|
||||
explicitly permitted to have a mixture of quoted and unquoted
|
||||
continuation fields.
|
||||
|
||||
4. Parameter Value Character Set and Language Information
|
||||
|
||||
Some parameter values may need to be qualified with character set or
|
||||
language information. It is clear that a distinguished parameter
|
||||
name is needed to identify when this information is present along
|
||||
with a specific syntax for the information in the value itself. In
|
||||
addition, a lightweight encoding mechanism is needed to accommodate 8
|
||||
bit information in parameter values.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 4]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
Asterisks ("*") are reused to provide the indicator that language and
|
||||
character set information is present and encoding is being used. A
|
||||
single quote ("'") is used to delimit the character set and language
|
||||
information at the beginning of the parameter value. Percent signs
|
||||
("%") are used as the encoding flag, which agrees with RFC 2047.
|
||||
|
||||
Specifically, an asterisk at the end of a parameter name acts as an
|
||||
indicator that character set and language information may appear at
|
||||
the beginning of the parameter value. A single quote is used to
|
||||
separate the character set, language, and actual value information in
|
||||
the parameter value string, and an percent sign is used to flag
|
||||
octets encoded in hexadecimal. For example:
|
||||
|
||||
Content-Type: application/x-stuff;
|
||||
title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A
|
||||
|
||||
Note that it is perfectly permissible to leave either the character
|
||||
set or language field blank. Note also that the single quote
|
||||
delimiters MUST be present even when one of the field values is
|
||||
omitted. This is done when either character set, language, or both
|
||||
are not relevant to the parameter value at hand. This MUST NOT be
|
||||
done in order to indicate a default character set or language --
|
||||
parameter field definitions MUST NOT assign a default character set
|
||||
or language.
|
||||
|
||||
4.1. Combining Character Set, Language, and Parameter Continuations
|
||||
|
||||
Character set and language information may be combined with the
|
||||
parameter continuation mechanism. For example:
|
||||
|
||||
Content-Type: application/x-stuff
|
||||
title*0*=us-ascii'en'This%20is%20even%20more%20
|
||||
title*1*=%2A%2A%2Afun%2A%2A%2A%20
|
||||
title*2="isn't it!"
|
||||
|
||||
Note that:
|
||||
|
||||
(1) Language and character set information only appear at
|
||||
the beginning of a given parameter value.
|
||||
|
||||
(2) Continuations do not provide a facility for using more
|
||||
than one character set or language in the same
|
||||
parameter value.
|
||||
|
||||
(3) A value presented using multiple continuations may
|
||||
contain a mixture of encoded and unencoded segments.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 5]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
(4) The first segment of a continuation MUST be encoded if
|
||||
language and character set information are given.
|
||||
|
||||
(5) If the first segment of a continued parameter value is
|
||||
encoded the language and character set field delimiters
|
||||
MUST be present even when the fields are left blank.
|
||||
|
||||
5. Language specification in Encoded Words
|
||||
|
||||
RFC 2047 provides support for non-US-ASCII character sets in RFC 822
|
||||
message header comments, phrases, and any unstructured text field.
|
||||
This is done by defining an encoded word construct which can appear
|
||||
in any of these places. Given that these are fields intended for
|
||||
display, it is sometimes necessary to associate language information
|
||||
with encoded words as well as just the character set. This
|
||||
specification extends the definition of an encoded word to allow the
|
||||
inclusion of such information. This is simply done by suffixing the
|
||||
character set specification with an asterisk followed by the language
|
||||
tag. For example:
|
||||
|
||||
From: =?US-ASCII*EN?Q?Keith_Moore?= <moore@cs.utk.edu>
|
||||
|
||||
6. IMAP4 Handling of Parameter Values
|
||||
|
||||
IMAP4 [RFC-2060] servers SHOULD decode parameter value continuations
|
||||
when generating the BODY and BODYSTRUCTURE fetch attributes.
|
||||
|
||||
7. Modifications to MIME ABNF
|
||||
|
||||
The ABNF for MIME parameter values given in RFC 2045 is:
|
||||
|
||||
parameter := attribute "=" value
|
||||
|
||||
attribute := token
|
||||
; Matching of attributes
|
||||
; is ALWAYS case-insensitive.
|
||||
|
||||
This specification changes this ABNF to:
|
||||
|
||||
parameter := regular-parameter / extended-parameter
|
||||
|
||||
regular-parameter := regular-parameter-name "=" value
|
||||
|
||||
regular-parameter-name := attribute [section]
|
||||
|
||||
attribute := 1*attribute-char
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 6]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
attribute-char := <any (US-ASCII) CHAR except SPACE, CTLs,
|
||||
"*", "'", "%", or tspecials>
|
||||
|
||||
section := initial-section / other-sections
|
||||
|
||||
initial-section := "*0"
|
||||
|
||||
other-sections := "*" ("1" / "2" / "3" / "4" / "5" /
|
||||
"6" / "7" / "8" / "9") *DIGIT)
|
||||
|
||||
extended-parameter := (extended-initial-name "="
|
||||
extended-value) /
|
||||
(extended-other-names "="
|
||||
extended-other-values)
|
||||
|
||||
extended-initial-name := attribute [initial-section] "*"
|
||||
|
||||
extended-other-names := attribute other-sections "*"
|
||||
|
||||
extended-initial-value := [charset] "'" [language] "'"
|
||||
extended-other-values
|
||||
|
||||
extended-other-values := *(ext-octet / attribute-char)
|
||||
|
||||
ext-octet := "%" 2(DIGIT / "A" / "B" / "C" / "D" / "E" / "F")
|
||||
|
||||
charset := <registered character set name>
|
||||
|
||||
language := <registered language tag [RFC-1766]>
|
||||
|
||||
The ABNF given in RFC 2047 for encoded-words is:
|
||||
|
||||
encoded-word := "=?" charset "?" encoding "?" encoded-text "?="
|
||||
|
||||
This specification changes this ABNF to:
|
||||
|
||||
encoded-word := "=?" charset ["*" language] "?" encoded-text "?="
|
||||
|
||||
8. Character sets which allow specification of language
|
||||
|
||||
In the future it is likely that some character sets will provide
|
||||
facilities for inline language labeling. Such facilities are
|
||||
inherently more flexible than those defined here as they allow for
|
||||
language switching in the middle of a string.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 7]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
If and when such facilities are developed they SHOULD be used in
|
||||
preference to the language labeling facilities specified here. Note
|
||||
that all the mechanisms defined here allow for the omission of
|
||||
language labels so as to be able to accommodate this possible future
|
||||
usage.
|
||||
|
||||
9. Security Considerations
|
||||
|
||||
This RFC does not discuss security issues and is not believed to
|
||||
raise any security issues not already endemic in electronic mail and
|
||||
present in fully conforming implementations of MIME.
|
||||
|
||||
10. References
|
||||
|
||||
[RFC-822]
|
||||
Crocker, D., "Standard for the Format of ARPA Internet
|
||||
Text Messages", STD 11, RFC 822 August 1982.
|
||||
|
||||
[RFC-1766]
|
||||
Alvestrand, H., "Tags for the Identification of
|
||||
Languages", RFC 1766, March 1995.
|
||||
|
||||
[RFC-2045]
|
||||
Freed, N., and N. Borenstein, "Multipurpose Internet Mail
|
||||
Extensions (MIME) Part One: Format of Internet Message
|
||||
Bodies", RFC 2045, December 1996.
|
||||
|
||||
[RFC-2046]
|
||||
Freed, N. and N. Borenstein, "Multipurpose Internet Mail
|
||||
Extensions (MIME) Part Two: Media Types", RFC 2046,
|
||||
December 1996.
|
||||
|
||||
[RFC-2047]
|
||||
Moore, K., "Multipurpose Internet Mail Extensions (MIME)
|
||||
Part Three: Representation of Non-ASCII Text in Internet
|
||||
Message Headers", RFC 2047, December 1996.
|
||||
|
||||
[RFC-2048]
|
||||
Freed, N., Klensin, J. and J. Postel, "Multipurpose
|
||||
Internet Mail Extensions (MIME) Part Four: MIME
|
||||
Registration Procedures", RFC 2048, December 1996.
|
||||
|
||||
[RFC-2049]
|
||||
Freed, N. and N. Borenstein, "Multipurpose Internet Mail
|
||||
Extensions (MIME) Part Five: Conformance Criteria and
|
||||
Examples", RFC 2049, December 1996.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 8]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
[RFC-2060]
|
||||
Crispin, M., "Internet Message Access Protocol - Version
|
||||
4rev1", RFC 2060, December 1996.
|
||||
|
||||
[RFC-2119]
|
||||
Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", RFC 2119, March 1997.
|
||||
|
||||
[RFC-2130]
|
||||
Weider, C., Preston, C., Simonsen, K., Alvestrand, H.,
|
||||
Atkinson, R., Crispin, M., and P. Svanberg, "Report from the
|
||||
IAB Character Set Workshop", RFC 2130, April 1997.
|
||||
|
||||
[RFC-2183]
|
||||
Troost, R., Dorner, S. and K. Moore, "Communicating
|
||||
Presentation Information in Internet Messages: The
|
||||
Content-Disposition Header", RFC 2183, August 1997.
|
||||
|
||||
11. Authors' Addresses
|
||||
|
||||
Ned Freed
|
||||
Innosoft International, Inc.
|
||||
1050 Lakes Drive
|
||||
West Covina, CA 91790
|
||||
USA
|
||||
|
||||
Phone: +1 626 919 3600
|
||||
Fax: +1 626 919 3614
|
||||
EMail: ned.freed@innosoft.com
|
||||
|
||||
|
||||
Keith Moore
|
||||
Computer Science Dept.
|
||||
University of Tennessee
|
||||
107 Ayres Hall
|
||||
Knoxville, TN 37996-1301
|
||||
USA
|
||||
|
||||
EMail: moore@cs.utk.edu
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 9]
|
||||
|
||||
RFC 2231 MIME Value and Encoded Word Extensions November 1997
|
||||
|
||||
|
||||
12. Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (1997). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Freed & Moore Standards Track [Page 10]
|
||||
|
|
@ -0,0 +1,787 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group D. Crocker, Ed.
|
||||
Request for Comments: 2234 Internet Mail Consortium
|
||||
Category: Standards Track P. Overell
|
||||
Demon Internet Ltd.
|
||||
November 1997
|
||||
|
||||
|
||||
Augmented BNF for Syntax Specifications: ABNF
|
||||
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (1997). All Rights Reserved.
|
||||
|
||||
TABLE OF CONTENTS
|
||||
|
||||
1. INTRODUCTION .................................................. 2
|
||||
|
||||
2. RULE DEFINITION ............................................... 2
|
||||
2.1 RULE NAMING .................................................. 2
|
||||
2.2 RULE FORM .................................................... 3
|
||||
2.3 TERMINAL VALUES .............................................. 3
|
||||
2.4 EXTERNAL ENCODINGS ........................................... 5
|
||||
|
||||
3. OPERATORS ..................................................... 5
|
||||
3.1 CONCATENATION RULE1 RULE2 ............................. 5
|
||||
3.2 ALTERNATIVES RULE1 / RULE2 ................................... 6
|
||||
3.3 INCREMENTAL ALTERNATIVES RULE1 =/ RULE2 .................... 6
|
||||
3.4 VALUE RANGE ALTERNATIVES %C##-## ........................... 7
|
||||
3.5 SEQUENCE GROUP (RULE1 RULE2) ................................. 7
|
||||
3.6 VARIABLE REPETITION *RULE .................................... 8
|
||||
3.7 SPECIFIC REPETITION NRULE .................................... 8
|
||||
3.8 OPTIONAL SEQUENCE [RULE] ..................................... 8
|
||||
3.9 ; COMMENT .................................................... 8
|
||||
3.10 OPERATOR PRECEDENCE ......................................... 9
|
||||
|
||||
4. ABNF DEFINITION OF ABNF ....................................... 9
|
||||
|
||||
5. SECURITY CONSIDERATIONS ....................................... 10
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 1]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
6. APPENDIX A - CORE ............................................. 11
|
||||
6.1 CORE RULES ................................................... 11
|
||||
6.2 COMMON ENCODING .............................................. 12
|
||||
|
||||
7. ACKNOWLEDGMENTS ............................................... 12
|
||||
|
||||
8. REFERENCES .................................................... 13
|
||||
|
||||
9. CONTACT ....................................................... 13
|
||||
|
||||
10. FULL COPYRIGHT STATEMENT ..................................... 14
|
||||
|
||||
1. INTRODUCTION
|
||||
|
||||
Internet technical specifications often need to define a format
|
||||
syntax and are free to employ whatever notation their authors deem
|
||||
useful. Over the years, a modified version of Backus-Naur Form
|
||||
(BNF), called Augmented BNF (ABNF), has been popular among many
|
||||
Internet specifications. It balances compactness and simplicity,
|
||||
with reasonable representational power. In the early days of the
|
||||
Arpanet, each specification contained its own definition of ABNF.
|
||||
This included the email specifications, RFC733 and then RFC822 which
|
||||
have come to be the common citations for defining ABNF. The current
|
||||
document separates out that definition, to permit selective
|
||||
reference. Predictably, it also provides some modifications and
|
||||
enhancements.
|
||||
|
||||
The differences between standard BNF and ABNF involve naming rules,
|
||||
repetition, alternatives, order-independence, and value ranges.
|
||||
Appendix A (Core) supplies rule definitions and encoding for a core
|
||||
lexical analyzer of the type common to several Internet
|
||||
specifications. It is provided as a convenience and is otherwise
|
||||
separate from the meta language defined in the body of this document,
|
||||
and separate from its formal status.
|
||||
|
||||
2. RULE DEFINITION
|
||||
|
||||
2.1 Rule Naming
|
||||
|
||||
The name of a rule is simply the name itself; that is, a sequence of
|
||||
characters, beginning with an alphabetic character, and followed by
|
||||
a combination of alphabetics, digits and hyphens (dashes).
|
||||
|
||||
NOTE: Rule names are case-insensitive
|
||||
|
||||
The names <rulename>, <Rulename>, <RULENAME> and <rUlENamE> all refer
|
||||
to the same rule.
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 2]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
Unlike original BNF, angle brackets ("<", ">") are not required.
|
||||
However, angle brackets may be used around a rule name whenever their
|
||||
presence will facilitate discerning the use of a rule name. This is
|
||||
typically restricted to rule name references in free-form prose, or
|
||||
to distinguish partial rules that combine into a string not separated
|
||||
by white space, such as shown in the discussion about repetition,
|
||||
below.
|
||||
|
||||
2.2 Rule Form
|
||||
|
||||
A rule is defined by the following sequence:
|
||||
|
||||
name = elements crlf
|
||||
|
||||
where <name> is the name of the rule, <elements> is one or more rule
|
||||
names or terminal specifications and <crlf> is the end-of- line
|
||||
indicator, carriage return followed by line feed. The equal sign
|
||||
separates the name from the definition of the rule. The elements
|
||||
form a sequence of one or more rule names and/or value definitions,
|
||||
combined according to the various operators, defined in this
|
||||
document, such as alternative and repetition.
|
||||
|
||||
For visual ease, rule definitions are left aligned. When a rule
|
||||
requires multiple lines, the continuation lines are indented. The
|
||||
left alignment and indentation are relative to the first lines of the
|
||||
ABNF rules and need not match the left margin of the document.
|
||||
|
||||
2.3 Terminal Values
|
||||
|
||||
Rules resolve into a string of terminal values, sometimes called
|
||||
characters. In ABNF a character is merely a non-negative integer.
|
||||
In certain contexts a specific mapping (encoding) of values into a
|
||||
character set (such as ASCII) will be specified.
|
||||
|
||||
Terminals are specified by one or more numeric characters with the
|
||||
base interpretation of those characters indicated explicitly. The
|
||||
following bases are currently defined:
|
||||
|
||||
b = binary
|
||||
|
||||
d = decimal
|
||||
|
||||
x = hexadecimal
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 3]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
Hence:
|
||||
|
||||
CR = %d13
|
||||
|
||||
CR = %x0D
|
||||
|
||||
respectively specify the decimal and hexadecimal representation of
|
||||
[US-ASCII] for carriage return.
|
||||
|
||||
A concatenated string of such values is specified compactly, using a
|
||||
period (".") to indicate separation of characters within that value.
|
||||
Hence:
|
||||
|
||||
CRLF = %d13.10
|
||||
|
||||
ABNF permits specifying literal text string directly, enclosed in
|
||||
quotation-marks. Hence:
|
||||
|
||||
command = "command string"
|
||||
|
||||
Literal text strings are interpreted as a concatenated set of
|
||||
printable characters.
|
||||
|
||||
NOTE: ABNF strings are case-insensitive and
|
||||
the character set for these strings is us-ascii.
|
||||
|
||||
Hence:
|
||||
|
||||
rulename = "abc"
|
||||
|
||||
and:
|
||||
|
||||
rulename = "aBc"
|
||||
|
||||
will match "abc", "Abc", "aBc", "abC", "ABc", "aBC", "AbC" and "ABC".
|
||||
|
||||
To specify a rule which IS case SENSITIVE,
|
||||
specify the characters individually.
|
||||
|
||||
For example:
|
||||
|
||||
rulename = %d97 %d98 %d99
|
||||
|
||||
or
|
||||
|
||||
rulename = %d97.98.99
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 4]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
will match only the string which comprises only lowercased
|
||||
characters, abc.
|
||||
|
||||
2.4 External Encodings
|
||||
|
||||
External representations of terminal value characters will vary
|
||||
according to constraints in the storage or transmission environment.
|
||||
Hence, the same ABNF-based grammar may have multiple external
|
||||
encodings, such as one for a 7-bit US-ASCII environment, another for
|
||||
a binary octet environment and still a different one when 16-bit
|
||||
Unicode is used. Encoding details are beyond the scope of ABNF,
|
||||
although Appendix A (Core) provides definitions for a 7-bit US-ASCII
|
||||
environment as has been common to much of the Internet.
|
||||
|
||||
By separating external encoding from the syntax, it is intended that
|
||||
alternate encoding environments can be used for the same syntax.
|
||||
|
||||
3. OPERATORS
|
||||
|
||||
3.1 Concatenation Rule1 Rule2
|
||||
|
||||
A rule can define a simple, ordered string of values -- i.e., a
|
||||
concatenation of contiguous characters -- by listing a sequence of
|
||||
rule names. For example:
|
||||
|
||||
foo = %x61 ; a
|
||||
|
||||
bar = %x62 ; b
|
||||
|
||||
mumble = foo bar foo
|
||||
|
||||
So that the rule <mumble> matches the lowercase string "aba".
|
||||
|
||||
LINEAR WHITE SPACE: Concatenation is at the core of the ABNF
|
||||
parsing model. A string of contiguous characters (values) is
|
||||
parsed according to the rules defined in ABNF. For Internet
|
||||
specifications, there is some history of permitting linear white
|
||||
space (space and horizontal tab) to be freelyPand
|
||||
implicitlyPinterspersed around major constructs, such as
|
||||
delimiting special characters or atomic strings.
|
||||
|
||||
NOTE: This specification for ABNF does not
|
||||
provide for implicit specification of linear white
|
||||
space.
|
||||
|
||||
Any grammar which wishes to permit linear white space around
|
||||
delimiters or string segments must specify it explicitly. It is
|
||||
often useful to provide for such white space in "core" rules that are
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 5]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
then used variously among higher-level rules. The "core" rules might
|
||||
be formed into a lexical analyzer or simply be part of the main
|
||||
ruleset.
|
||||
|
||||
3.2 Alternatives Rule1 / Rule2
|
||||
|
||||
Elements separated by forward slash ("/") are alternatives.
|
||||
Therefore,
|
||||
|
||||
foo / bar
|
||||
|
||||
will accept <foo> or <bar>.
|
||||
|
||||
NOTE: A quoted string containing alphabetic
|
||||
characters is special form for specifying alternative
|
||||
characters and is interpreted as a non-terminal
|
||||
representing the set of combinatorial strings with the
|
||||
contained characters, in the specified order but with
|
||||
any mixture of upper and lower case..
|
||||
|
||||
3.3 Incremental Alternatives Rule1 =/ Rule2
|
||||
|
||||
It is sometimes convenient to specify a list of alternatives in
|
||||
fragments. That is, an initial rule may match one or more
|
||||
alternatives, with later rule definitions adding to the set of
|
||||
alternatives. This is particularly useful for otherwise- independent
|
||||
specifications which derive from the same parent rule set, such as
|
||||
often occurs with parameter lists. ABNF permits this incremental
|
||||
definition through the construct:
|
||||
|
||||
oldrule =/ additional-alternatives
|
||||
|
||||
So that the rule set
|
||||
|
||||
ruleset = alt1 / alt2
|
||||
|
||||
ruleset =/ alt3
|
||||
|
||||
ruleset =/ alt4 / alt5
|
||||
|
||||
is the same as specifying
|
||||
|
||||
ruleset = alt1 / alt2 / alt3 / alt4 / alt5
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 6]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
3.4 Value Range Alternatives %c##-##
|
||||
|
||||
A range of alternative numeric values can be specified compactly,
|
||||
using dash ("-") to indicate the range of alternative values. Hence:
|
||||
|
||||
DIGIT = %x30-39
|
||||
|
||||
is equivalent to:
|
||||
|
||||
DIGIT = "0" / "1" / "2" / "3" / "4" / "5" / "6" /
|
||||
|
||||
"7" / "8" / "9"
|
||||
|
||||
Concatenated numeric values and numeric value ranges can not be
|
||||
specified in the same string. A numeric value may use the dotted
|
||||
notation for concatenation or it may use the dash notation to specify
|
||||
one value range. Hence, to specify one printable character, between
|
||||
end of line sequences, the specification could be:
|
||||
|
||||
char-line = %x0D.0A %x20-7E %x0D.0A
|
||||
|
||||
3.5 Sequence Group (Rule1 Rule2)
|
||||
|
||||
Elements enclosed in parentheses are treated as a single element,
|
||||
whose contents are STRICTLY ORDERED. Thus,
|
||||
|
||||
elem (foo / bar) blat
|
||||
|
||||
which matches (elem foo blat) or (elem bar blat).
|
||||
|
||||
elem foo / bar blat
|
||||
|
||||
matches (elem foo) or (bar blat).
|
||||
|
||||
NOTE: It is strongly advised to use grouping
|
||||
notation, rather than to rely on proper reading of
|
||||
"bare" alternations, when alternatives consist of
|
||||
multiple rule names or literals.
|
||||
|
||||
Hence it is recommended that instead of the above form, the form:
|
||||
|
||||
(elem foo) / (bar blat)
|
||||
|
||||
be used. It will avoid misinterpretation by casual readers.
|
||||
|
||||
The sequence group notation is also used within free text to set off
|
||||
an element sequence from the prose.
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 7]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
3.6 Variable Repetition *Rule
|
||||
|
||||
The operator "*" preceding an element indicates repetition. The full
|
||||
form is:
|
||||
|
||||
<a>*<b>element
|
||||
|
||||
where <a> and <b> are optional decimal values, indicating at least
|
||||
<a> and at most <b> occurrences of element.
|
||||
|
||||
Default values are 0 and infinity so that *<element> allows any
|
||||
number, including zero; 1*<element> requires at least one;
|
||||
3*3<element> allows exactly 3 and 1*2<element> allows one or two.
|
||||
|
||||
3.7 Specific Repetition nRule
|
||||
|
||||
A rule of the form:
|
||||
|
||||
<n>element
|
||||
|
||||
is equivalent to
|
||||
|
||||
<n>*<n>element
|
||||
|
||||
That is, exactly <N> occurrences of <element>. Thus 2DIGIT is a
|
||||
2-digit number, and 3ALPHA is a string of three alphabetic
|
||||
characters.
|
||||
|
||||
3.8 Optional Sequence [RULE]
|
||||
|
||||
Square brackets enclose an optional element sequence:
|
||||
|
||||
[foo bar]
|
||||
|
||||
is equivalent to
|
||||
|
||||
*1(foo bar).
|
||||
|
||||
3.9 ; Comment
|
||||
|
||||
A semi-colon starts a comment that continues to the end of line.
|
||||
This is a simple way of including useful notes in parallel with the
|
||||
specifications.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 8]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
3.10 Operator Precedence
|
||||
|
||||
The various mechanisms described above have the following precedence,
|
||||
from highest (binding tightest) at the top, to lowest and loosest at
|
||||
the bottom:
|
||||
|
||||
Strings, Names formation
|
||||
Comment
|
||||
Value range
|
||||
Repetition
|
||||
Grouping, Optional
|
||||
Concatenation
|
||||
Alternative
|
||||
|
||||
Use of the alternative operator, freely mixed with concatenations can
|
||||
be confusing.
|
||||
|
||||
Again, it is recommended that the grouping operator be used to
|
||||
make explicit concatenation groups.
|
||||
|
||||
4. ABNF DEFINITION OF ABNF
|
||||
|
||||
This syntax uses the rules provided in Appendix A (Core).
|
||||
|
||||
rulelist = 1*( rule / (*c-wsp c-nl) )
|
||||
|
||||
rule = rulename defined-as elements c-nl
|
||||
; continues if next line starts
|
||||
; with white space
|
||||
|
||||
rulename = ALPHA *(ALPHA / DIGIT / "-")
|
||||
|
||||
defined-as = *c-wsp ("=" / "=/") *c-wsp
|
||||
; basic rules definition and
|
||||
; incremental alternatives
|
||||
|
||||
elements = alternation *c-wsp
|
||||
|
||||
c-wsp = WSP / (c-nl WSP)
|
||||
|
||||
c-nl = comment / CRLF
|
||||
; comment or newline
|
||||
|
||||
comment = ";" *(WSP / VCHAR) CRLF
|
||||
|
||||
alternation = concatenation
|
||||
*(*c-wsp "/" *c-wsp concatenation)
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 9]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
concatenation = repetition *(1*c-wsp repetition)
|
||||
|
||||
repetition = [repeat] element
|
||||
|
||||
repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)
|
||||
|
||||
element = rulename / group / option /
|
||||
char-val / num-val / prose-val
|
||||
|
||||
group = "(" *c-wsp alternation *c-wsp ")"
|
||||
|
||||
option = "[" *c-wsp alternation *c-wsp "]"
|
||||
|
||||
char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
|
||||
; quoted string of SP and VCHAR
|
||||
without DQUOTE
|
||||
|
||||
num-val = "%" (bin-val / dec-val / hex-val)
|
||||
|
||||
bin-val = "b" 1*BIT
|
||||
[ 1*("." 1*BIT) / ("-" 1*BIT) ]
|
||||
; series of concatenated bit values
|
||||
; or single ONEOF range
|
||||
|
||||
dec-val = "d" 1*DIGIT
|
||||
[ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
|
||||
|
||||
hex-val = "x" 1*HEXDIG
|
||||
[ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
|
||||
|
||||
prose-val = "<" *(%x20-3D / %x3F-7E) ">"
|
||||
; bracketed string of SP and VCHAR
|
||||
without angles
|
||||
; prose description, to be used as
|
||||
last resort
|
||||
|
||||
|
||||
5. SECURITY CONSIDERATIONS
|
||||
|
||||
Security is truly believed to be irrelevant to this document.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 10]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
6. APPENDIX A - CORE
|
||||
|
||||
This Appendix is provided as a convenient core for specific grammars.
|
||||
The definitions may be used as a core set of rules.
|
||||
|
||||
6.1 Core Rules
|
||||
|
||||
Certain basic rules are in uppercase, such as SP, HTAB, CRLF,
|
||||
DIGIT, ALPHA, etc.
|
||||
|
||||
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
|
||||
|
||||
BIT = "0" / "1"
|
||||
|
||||
CHAR = %x01-7F
|
||||
; any 7-bit US-ASCII character,
|
||||
excluding NUL
|
||||
|
||||
CR = %x0D
|
||||
; carriage return
|
||||
|
||||
CRLF = CR LF
|
||||
; Internet standard newline
|
||||
|
||||
CTL = %x00-1F / %x7F
|
||||
; controls
|
||||
|
||||
DIGIT = %x30-39
|
||||
; 0-9
|
||||
|
||||
DQUOTE = %x22
|
||||
; " (Double Quote)
|
||||
|
||||
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
|
||||
|
||||
HTAB = %x09
|
||||
; horizontal tab
|
||||
|
||||
LF = %x0A
|
||||
; linefeed
|
||||
|
||||
LWSP = *(WSP / CRLF WSP)
|
||||
; linear white space (past newline)
|
||||
|
||||
OCTET = %x00-FF
|
||||
; 8 bits of data
|
||||
|
||||
SP = %x20
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 11]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
; space
|
||||
|
||||
VCHAR = %x21-7E
|
||||
; visible (printing) characters
|
||||
|
||||
WSP = SP / HTAB
|
||||
; white space
|
||||
|
||||
6.2 Common Encoding
|
||||
|
||||
Externally, data are represented as "network virtual ASCII", namely
|
||||
7-bit US-ASCII in an 8-bit field, with the high (8th) bit set to
|
||||
zero. A string of values is in "network byte order" with the
|
||||
higher-valued bytes represented on the left-hand side and being sent
|
||||
over the network first.
|
||||
|
||||
7. ACKNOWLEDGMENTS
|
||||
|
||||
The syntax for ABNF was originally specified in RFC 733. Ken L.
|
||||
Harrenstien, of SRI International, was responsible for re-coding the
|
||||
BNF into an augmented BNF that makes the representation smaller and
|
||||
easier to understand.
|
||||
|
||||
This recent project began as a simple effort to cull out the portion
|
||||
of RFC 822 which has been repeatedly cited by non-email specification
|
||||
writers, namely the description of augmented BNF. Rather than simply
|
||||
and blindly converting the existing text into a separate document,
|
||||
the working group chose to give careful consideration to the
|
||||
deficiencies, as well as benefits, of the existing specification and
|
||||
related specifications available over the last 15 years and therefore
|
||||
to pursue enhancement. This turned the project into something rather
|
||||
more ambitious than first intended. Interestingly the result is not
|
||||
massively different from that original, although decisions such as
|
||||
removing the list notation came as a surprise.
|
||||
|
||||
The current round of specification was part of the DRUMS working
|
||||
group, with significant contributions from Jerome Abela , Harald
|
||||
Alvestrand, Robert Elz, Roger Fajman, Aviva Garrett, Tom Harsch, Dan
|
||||
Kohn, Bill McQuillan, Keith Moore, Chris Newman , Pete Resnick and
|
||||
Henning Schulzrinne.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 12]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
8. REFERENCES
|
||||
|
||||
[US-ASCII] Coded Character Set--7-Bit American Standard Code for
|
||||
Information Interchange, ANSI X3.4-1986.
|
||||
|
||||
[RFC733] Crocker, D., Vittal, J., Pogran, K., and D. Henderson,
|
||||
"Standard for the Format of ARPA Network Text Message," RFC 733,
|
||||
November 1977.
|
||||
|
||||
[RFC822] Crocker, D., "Standard for the Format of ARPA Internet Text
|
||||
Messages", STD 11, RFC 822, August 1982.
|
||||
|
||||
9. CONTACT
|
||||
|
||||
David H. Crocker Paul Overell
|
||||
|
||||
Internet Mail Consortium Demon Internet Ltd
|
||||
675 Spruce Dr. Dorking Business Park
|
||||
Sunnyvale, CA 94086 USA Dorking
|
||||
Surrey, RH4 1HN
|
||||
UK
|
||||
|
||||
Phone: +1 408 246 8253
|
||||
Fax: +1 408 249 6205
|
||||
EMail: dcrocker@imc.org paulo@turnpike.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 13]
|
||||
|
||||
RFC 2234 ABNF for Syntax Specifications November 1997
|
||||
|
||||
|
||||
10. Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (1997). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Crocker & Overell Standards Track [Page 14]
|
||||
|
|
@ -0,0 +1,451 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group P. Hoffman
|
||||
Request for Comments: 2487 Internet Mail Consortium
|
||||
Category: Standards Track January 1999
|
||||
|
||||
|
||||
SMTP Service Extension for Secure SMTP over TLS
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (1999). All Rights Reserved.
|
||||
|
||||
1. Abstract
|
||||
|
||||
This document describes an extension to the SMTP service that allows
|
||||
an SMTP server and client to use transport-layer security to provide
|
||||
private, authenticated communication over the Internet. This gives
|
||||
SMTP agents the ability to protect some or all of their
|
||||
communications from eavesdroppers and attackers.
|
||||
|
||||
2. Introduction
|
||||
|
||||
SMTP [RFC-821] servers and clients normally communicate in the clear
|
||||
over the Internet. In many cases, this communication goes through one
|
||||
or more router that is not controlled or trusted by either entity.
|
||||
Such an untrusted router might allow a third party to monitor or
|
||||
alter the communications between the server and client.
|
||||
|
||||
Further, there is often a desire for two SMTP agents to be able to
|
||||
authenticate each others' identities. For example, a secure SMTP
|
||||
server might only allow communications from other SMTP agents it
|
||||
knows, or it might act differently for messages received from an
|
||||
agent it knows than from one it doesn't know.
|
||||
|
||||
TLS [TLS], more commonly known as SSL, is a popular mechanism for
|
||||
enhancing TCP communications with privacy and authentication. TLS is
|
||||
in wide use with the HTTP protocol, and is also being used for adding
|
||||
security to many other common protocols that run over TCP.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 1]
|
||||
|
||||
RFC 2487 SMTP Service Extension January 1999
|
||||
|
||||
|
||||
2.1 Terminology
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [RFC-2119].
|
||||
|
||||
3. STARTTLS Extension
|
||||
|
||||
The STARTTLS extension to SMTP is laid out as follows:
|
||||
|
||||
(1) the name of the SMTP service defined here is STARTTLS;
|
||||
|
||||
(2) the EHLO keyword value associated with the extension is STARTTLS;
|
||||
|
||||
(3) the STARTTLS keyword has no parameters;
|
||||
|
||||
(4) a new SMTP verb, "STARTTLS", is defined;
|
||||
|
||||
(5) no additional parameters are added to any SMTP command.
|
||||
|
||||
4. The STARTTLS Keyword
|
||||
|
||||
The STARTTLS keyword is used to tell the SMTP client that the SMTP
|
||||
server allows use of TLS. It takes no parameters.
|
||||
|
||||
5. The STARTTLS Command
|
||||
|
||||
The format for the STARTTLS command is:
|
||||
|
||||
STARTTLS
|
||||
|
||||
with no parameters.
|
||||
|
||||
After the client gives the STARTTLS command, the server responds with
|
||||
one of the following reply codes:
|
||||
|
||||
220 Ready to start TLS
|
||||
501 Syntax error (no parameters allowed)
|
||||
454 TLS not available due to temporary reason
|
||||
|
||||
A publicly-referenced SMTP server MUST NOT require use of the
|
||||
STARTTLS extension in order to deliver mail locally. This rule
|
||||
prevents the STARTTLS extension from damaging the interoperability of
|
||||
the Internet's SMTP infrastructure. A publicly-referenced SMTP server
|
||||
is an SMTP server which runs on port 25 of an Internet host listed in
|
||||
the MX record (or A record if an MX record is not present) for the
|
||||
domain name on the right hand side of an Internet mail address.
|
||||
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 2]
|
||||
|
||||
RFC 2487 SMTP Service Extension January 1999
|
||||
|
||||
|
||||
Any SMTP server may refuse to accept messages for relay based on
|
||||
authentication supplied during the TLS negotiation. An SMTP server
|
||||
that is not publicly referenced may refuse to accept any messages for
|
||||
relay or local delivery based on authentication supplied during the
|
||||
TLS negotiation.
|
||||
|
||||
A SMTP server that is not publicly referenced may choose to require
|
||||
that the client perform a TLS negotiation before accepting any
|
||||
commands. In this case, the server SHOULD return the reply code:
|
||||
|
||||
530 Must issue a STARTTLS command first
|
||||
|
||||
to every command other than NOOP, EHLO, STARTTLS, or QUIT. If the
|
||||
client and server are using the ENHANCEDSTATUSCODES ESMTP extension
|
||||
[RFC-2034], the status code to be returned SHOULD be 5.7.0.
|
||||
|
||||
After receiving a 220 response to a STARTTLS command, the client
|
||||
SHOULD start the TLS negotiation before giving any other SMTP
|
||||
commands.
|
||||
|
||||
If the SMTP client is using pipelining as defined in RFC 1854, the
|
||||
STARTTLS command must be the last command in a group.
|
||||
|
||||
5.1 Processing After the STARTTLS Command
|
||||
|
||||
After the TLS handshake has been completed, both parties MUST
|
||||
immediately decide whether or not to continue based on the
|
||||
authentication and privacy achieved. The SMTP client and server may
|
||||
decide to move ahead even if the TLS negotiation ended with no
|
||||
authentication and/or no privacy because most SMTP services are
|
||||
performed with no authentication and no privacy, but some SMTP
|
||||
clients or servers may want to continue only if a particular level of
|
||||
authentication and/or privacy was achieved.
|
||||
|
||||
If the SMTP client decides that the level of authentication or
|
||||
privacy is not high enough for it to continue, it SHOULD issue an
|
||||
SMTP QUIT command immediately after the TLS negotiation is complete.
|
||||
If the SMTP server decides that the level of authentication or
|
||||
privacy is not high enough for it to continue, it SHOULD reply to
|
||||
every SMTP command from the client (other than a QUIT command) with
|
||||
the 554 reply code (with a possible text string such as "Command
|
||||
refused due to lack of security").
|
||||
|
||||
The decision of whether or not to believe the authenticity of the
|
||||
other party in a TLS negotiation is a local matter. However, some
|
||||
general rules for the decisions are:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 3]
|
||||
|
||||
RFC 2487 SMTP Service Extension January 1999
|
||||
|
||||
|
||||
- A SMTP client would probably only want to authenticate an SMTP
|
||||
server whose server certificate has a domain name that is the
|
||||
domain name that the client thought it was connecting to.
|
||||
- A publicly-referenced SMTP server would probably want to accept
|
||||
any certificate from an SMTP client, and would possibly want to
|
||||
put distinguishing information about the certificate in the
|
||||
Received header of messages that were relayed or submitted from
|
||||
the client.
|
||||
|
||||
5.2 Result of the STARTTLS Command
|
||||
|
||||
Upon completion of the TLS handshake, the SMTP protocol is reset to
|
||||
the initial state (the state in SMTP after a server issues a 220
|
||||
service ready greeting). The server MUST discard any knowledge
|
||||
obtained from the client, such as the argument to the EHLO command,
|
||||
which was not obtained from the TLS negotiation itself. The client
|
||||
MUST discard any knowledge obtained from the server, such as the list
|
||||
of SMTP service extensions, which was not obtained from the TLS
|
||||
negotiation itself. The client SHOULD send an EHLO command as the
|
||||
first command after a successful TLS negotiation.
|
||||
|
||||
The list of SMTP service extensions returned in response to an EHLO
|
||||
command received after the TLS handshake MAY be different than the
|
||||
list returned before the TLS handshake. For example, an SMTP server
|
||||
might not want to advertise support for a particular SASL mechanism
|
||||
[SASL] unless a client has sent an appropriate client certificate
|
||||
during a TLS handshake.
|
||||
|
||||
Both the client and the server MUST know if there is a TLS session
|
||||
active. A client MUST NOT attempt to start a TLS session if a TLS
|
||||
session is already active. A server MUST NOT return the TLS extension
|
||||
in response to an EHLO command received after a TLS handshake has
|
||||
completed.
|
||||
|
||||
6. Usage Example
|
||||
|
||||
The following dialog illustrates how a client and server can start a
|
||||
TLS session:
|
||||
|
||||
S: <waits for connection on TCP port 25>
|
||||
C: <opens connection>
|
||||
S: 220 mail.imc.org SMTP service ready
|
||||
C: EHLO mail.ietf.org
|
||||
S: 250-mail.imc.org offers a warm hug of welcome
|
||||
S: 250 STARTTLS
|
||||
C: STARTTLS
|
||||
S: 220 Go ahead
|
||||
C: <starts TLS negotiation>
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 4]
|
||||
|
||||
RFC 2487 SMTP Service Extension January 1999
|
||||
|
||||
|
||||
C & S: <negotiate a TLS session>
|
||||
C & S: <check result of negotiation>
|
||||
C: <continues by sending an SMTP command>
|
||||
. . .
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
It should be noted that SMTP is not an end-to-end mechanism. Thus, if
|
||||
an SMTP client/server pair decide to add TLS privacy, they are not
|
||||
securing the transport from the originating mail user agent to the
|
||||
recipient. Further, because delivery of a single piece of mail may
|
||||
go between more than two SMTP servers, adding TLS privacy to one pair
|
||||
of servers does not mean that the entire SMTP chain has been made
|
||||
private. Further, just because an SMTP server can authenticate an
|
||||
SMTP client, it does not mean that the mail from the SMTP client was
|
||||
authenticated by the SMTP client when the client received it.
|
||||
|
||||
Both the STMP client and server must check the result of the TLS
|
||||
negotiation to see whether acceptable authentication or privacy was
|
||||
achieved. Ignoring this step completely invalidates using TLS for
|
||||
security. The decision about whether acceptable authentication or
|
||||
privacy was achieved is made locally, is implementation-dependant,
|
||||
and is beyond the scope of this document.
|
||||
|
||||
The SMTP client and server should note carefully the result of the
|
||||
TLS negotiation. If the negotiation results in no privacy, or if it
|
||||
results in privacy using algorithms or key lengths that are deemed
|
||||
not strong enough, or if the authentication is not good enough for
|
||||
either party, the client may choose to end the SMTP session with an
|
||||
immediate QUIT command, or the server may choose to not accept any
|
||||
more SMTP commands.
|
||||
|
||||
A server announcing in an EHLO response that it uses a particular TLS
|
||||
protocol should not pose any security issues, since any use of TLS
|
||||
will be at least as secure as no use of TLS.
|
||||
|
||||
A man-in-the-middle attack can be launched by deleting the "250
|
||||
STARTTLS" response from the server. This would cause the client not
|
||||
to try to start a TLS session. An SMTP client can protect against
|
||||
this attack by recording the fact that a particular SMTP server
|
||||
offers TLS during one session and generating an alarm if it does not
|
||||
appear in the EHLO response for a later session. The lack of TLS
|
||||
during a session SHOULD NOT result in the bouncing of email, although
|
||||
it could result in delayed processing.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 5]
|
||||
|
||||
RFC 2487 SMTP Service Extension January 1999
|
||||
|
||||
|
||||
Before the TLS handshake has begun, any protocol interactions are
|
||||
performed in the clear and may be modified by an active attacker. For
|
||||
this reason, clients and servers MUST discard any knowledge obtained
|
||||
prior to the start of the TLS handshake upon completion of the TLS
|
||||
handshake.
|
||||
|
||||
The STARTTLS extension is not suitable for authenticating the author
|
||||
of an email message unless every hop in the delivery chain, including
|
||||
the submission to the first SMTP server, is authenticated. Another
|
||||
proposal [SMTP-AUTH] can be used to authenticate delivery and MIME
|
||||
security multiparts [MIME-SEC] can be used to authenticate the author
|
||||
of an email message. In addition, the [SMTP-AUTH] proposal offers
|
||||
simpler and more flexible options to authenticate an SMTP client and
|
||||
the SASL EXTERNAL mechanism [SASL] MAY be used in conjunction with
|
||||
the STARTTLS command to provide an authorization identity.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 6]
|
||||
|
||||
RFC 2487 SMTP Service Extension January 1999
|
||||
|
||||
|
||||
A. References
|
||||
|
||||
[RFC-821] Postel, J., "Simple Mail Transfer Protocol", RFC 821,
|
||||
August 1982.
|
||||
|
||||
[RFC-1869] Klensin, J., Freed, N, Rose, M, Stefferud, E. and D.
|
||||
Crocker, "SMTP Service Extensions", STD 10, RFC 1869,
|
||||
November 1995.
|
||||
|
||||
[RFC-2034] Freed, N., "SMTP Service Extension for Returning Enhanced
|
||||
Error Codes", RFC 2034, October 1996.
|
||||
|
||||
[RFC-2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[SASL] Myers, J., "Simple Authentication and Security Layer
|
||||
(SASL)", RFC 2222, October 1997.
|
||||
|
||||
[SMTP-AUTH] "SMTP Service Extension for Authentication", Work in
|
||||
Progress.
|
||||
|
||||
[TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
|
||||
RFC 2246, January 1999.
|
||||
|
||||
B. Author's Address
|
||||
|
||||
Paul Hoffman
|
||||
Internet Mail Consortium
|
||||
127 Segre Place
|
||||
Santa Cruz, CA 95060
|
||||
|
||||
Phone: (831) 426-9827
|
||||
EMail: phoffman@imc.org
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 7]
|
||||
|
||||
RFC 2487 SMTP Service Extension January 1999
|
||||
|
||||
|
||||
C. Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (1999). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Hoffman Standards Track [Page 8]
|
||||
|
|
@ -0,0 +1,619 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group J. Myers
|
||||
Request for Comments: 2554 Netscape Communications
|
||||
Category: Standards Track March 1999
|
||||
|
||||
|
||||
SMTP Service Extension
|
||||
for Authentication
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (1999). All Rights Reserved.
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
This document defines an SMTP service extension [ESMTP] whereby an
|
||||
SMTP client may indicate an authentication mechanism to the server,
|
||||
perform an authentication protocol exchange, and optionally negotiate
|
||||
a security layer for subsequent protocol interactions. This
|
||||
extension is a profile of the Simple Authentication and Security
|
||||
Layer [SASL].
|
||||
|
||||
|
||||
2. Conventions Used in this Document
|
||||
|
||||
In examples, "C:" and "S:" indicate lines sent by the client and
|
||||
server respectively.
|
||||
|
||||
The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY"
|
||||
in this document are to be interpreted as defined in "Key words for
|
||||
use in RFCs to Indicate Requirement Levels" [KEYWORDS].
|
||||
|
||||
|
||||
3. The Authentication service extension
|
||||
|
||||
|
||||
(1) the name of the SMTP service extension is "Authentication"
|
||||
|
||||
(2) the EHLO keyword value associated with this extension is "AUTH"
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 1]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
(3) The AUTH EHLO keyword contains as a parameter a space separated
|
||||
list of the names of supported SASL mechanisms.
|
||||
|
||||
(4) a new SMTP verb "AUTH" is defined
|
||||
|
||||
(5) an optional parameter using the keyword "AUTH" is added to the
|
||||
MAIL FROM command, and extends the maximum line length of the
|
||||
MAIL FROM command by 500 characters.
|
||||
|
||||
(6) this extension is appropriate for the submission protocol
|
||||
[SUBMIT].
|
||||
|
||||
|
||||
4. The AUTH command
|
||||
|
||||
AUTH mechanism [initial-response]
|
||||
|
||||
Arguments:
|
||||
a string identifying a SASL authentication mechanism.
|
||||
an optional base64-encoded response
|
||||
|
||||
Restrictions:
|
||||
After an AUTH command has successfully completed, no more AUTH
|
||||
commands may be issued in the same session. After a successful
|
||||
AUTH command completes, a server MUST reject any further AUTH
|
||||
commands with a 503 reply.
|
||||
|
||||
The AUTH command is not permitted during a mail transaction.
|
||||
|
||||
Discussion:
|
||||
The AUTH command indicates an authentication mechanism to the
|
||||
server. If the server supports the requested authentication
|
||||
mechanism, it performs an authentication protocol exchange to
|
||||
authenticate and identify the user. Optionally, it also
|
||||
negotiates a security layer for subsequent protocol
|
||||
interactions. If the requested authentication mechanism is not
|
||||
supported, the server rejects the AUTH command with a 504
|
||||
reply.
|
||||
|
||||
The authentication protocol exchange consists of a series of
|
||||
server challenges and client answers that are specific to the
|
||||
authentication mechanism. A server challenge, otherwise known
|
||||
as a ready response, is a 334 reply with the text part
|
||||
containing a BASE64 encoded string. The client answer consists
|
||||
of a line containing a BASE64 encoded string. If the client
|
||||
wishes to cancel an authentication exchange, it issues a line
|
||||
with a single "*". If the server receives such an answer, it
|
||||
MUST reject the AUTH command by sending a 501 reply.
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 2]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
The optional initial-response argument to the AUTH command is
|
||||
used to save a round trip when using authentication mechanisms
|
||||
that are defined to send no data in the initial challenge.
|
||||
When the initial-response argument is used with such a
|
||||
mechanism, the initial empty challenge is not sent to the
|
||||
client and the server uses the data in the initial-response
|
||||
argument as if it were sent in response to the empty challenge.
|
||||
Unlike a zero-length client answer to a 334 reply, a zero-
|
||||
length initial response is sent as a single equals sign ("=").
|
||||
If the client uses an initial-response argument to the AUTH
|
||||
command with a mechanism that sends data in the initial
|
||||
challenge, the server rejects the AUTH command with a 535
|
||||
reply.
|
||||
|
||||
If the server cannot BASE64 decode the argument, it rejects the
|
||||
AUTH command with a 501 reply. If the server rejects the
|
||||
authentication data, it SHOULD reject the AUTH command with a
|
||||
535 reply unless a more specific error code, such as one listed
|
||||
in section 6, is appropriate. Should the client successfully
|
||||
complete the authentication exchange, the SMTP server issues a
|
||||
235 reply.
|
||||
|
||||
The service name specified by this protocol's profile of SASL
|
||||
is "smtp".
|
||||
|
||||
If a security layer is negotiated through the SASL
|
||||
authentication exchange, it takes effect immediately following
|
||||
the CRLF that concludes the authentication exchange for the
|
||||
client, and the CRLF of the success reply for the server. Upon
|
||||
a security layer's taking effect, the SMTP protocol is reset to
|
||||
the initial state (the state in SMTP after a server issues a
|
||||
220 service ready greeting). The server MUST discard any
|
||||
knowledge obtained from the client, such as the argument to the
|
||||
EHLO command, which was not obtained from the SASL negotiation
|
||||
itself. The client MUST discard any knowledge obtained from
|
||||
the server, such as the list of SMTP service extensions, which
|
||||
was not obtained from the SASL negotiation itself (with the
|
||||
exception that a client MAY compare the list of advertised SASL
|
||||
mechanisms before and after authentication in order to detect
|
||||
an active down-negotiation attack). The client SHOULD send an
|
||||
EHLO command as the first command after a successful SASL
|
||||
negotiation which results in the enabling of a security layer.
|
||||
|
||||
The server is not required to support any particular
|
||||
authentication mechanism, nor are authentication mechanisms
|
||||
required to support any security layers. If an AUTH command
|
||||
fails, the client may try another authentication mechanism by
|
||||
issuing another AUTH command.
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 3]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
If an AUTH command fails, the server MUST behave the same as if
|
||||
the client had not issued the AUTH command.
|
||||
|
||||
The BASE64 string may in general be arbitrarily long. Clients
|
||||
and servers MUST be able to support challenges and responses
|
||||
that are as long as are generated by the authentication
|
||||
mechanisms they support, independent of any line length
|
||||
limitations the client or server may have in other parts of its
|
||||
protocol implementation.
|
||||
|
||||
Examples:
|
||||
S: 220 smtp.example.com ESMTP server ready
|
||||
C: EHLO jgm.example.com
|
||||
S: 250-smtp.example.com
|
||||
S: 250 AUTH CRAM-MD5 DIGEST-MD5
|
||||
C: AUTH FOOBAR
|
||||
S: 504 Unrecognized authentication type.
|
||||
C: AUTH CRAM-MD5
|
||||
S: 334
|
||||
PENCeUxFREJoU0NnbmhNWitOMjNGNndAZWx3b29kLmlubm9zb2Z0LmNvbT4=
|
||||
C: ZnJlZCA5ZTk1YWVlMDljNDBhZjJiODRhMGMyYjNiYmFlNzg2ZQ==
|
||||
S: 235 Authentication successful.
|
||||
|
||||
|
||||
|
||||
5. The AUTH parameter to the MAIL FROM command
|
||||
|
||||
AUTH=addr-spec
|
||||
|
||||
Arguments:
|
||||
An addr-spec containing the identity which submitted the message
|
||||
to the delivery system, or the two character sequence "<>"
|
||||
indicating such an identity is unknown or insufficiently
|
||||
authenticated. To comply with the restrictions imposed on ESMTP
|
||||
parameters, the addr-spec is encoded inside an xtext. The syntax
|
||||
of an xtext is described in section 5 of [ESMTP-DSN].
|
||||
|
||||
Discussion:
|
||||
The optional AUTH parameter to the MAIL FROM command allows
|
||||
cooperating agents in a trusted environment to communicate the
|
||||
authentication of individual messages.
|
||||
|
||||
If the server trusts the authenticated identity of the client to
|
||||
assert that the message was originally submitted by the supplied
|
||||
addr-spec, then the server SHOULD supply the same addr-spec in an
|
||||
AUTH parameter when relaying the message to any server which
|
||||
supports the AUTH extension.
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 4]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
A MAIL FROM parameter of AUTH=<> indicates that the original
|
||||
submitter of the message is not known. The server MUST NOT treat
|
||||
the message as having been originally submitted by the client.
|
||||
|
||||
If the AUTH parameter to the MAIL FROM is not supplied, the
|
||||
client has authenticated, and the server believes the message is
|
||||
an original submission by the client, the server MAY supply the
|
||||
client's identity in the addr-spec in an AUTH parameter when
|
||||
relaying the message to any server which supports the AUTH
|
||||
extension.
|
||||
|
||||
If the server does not sufficiently trust the authenticated
|
||||
identity of the client, or if the client is not authenticated,
|
||||
then the server MUST behave as if the AUTH=<> parameter was
|
||||
supplied. The server MAY, however, write the value of the AUTH
|
||||
parameter to a log file.
|
||||
|
||||
If an AUTH=<> parameter was supplied, either explicitly or due to
|
||||
the requirement in the previous paragraph, then the server MUST
|
||||
supply the AUTH=<> parameter when relaying the message to any
|
||||
server which it has authenticated to using the AUTH extension.
|
||||
|
||||
A server MAY treat expansion of a mailing list as a new
|
||||
submission, setting the AUTH parameter to the mailing list
|
||||
address or mailing list administration address when relaying the
|
||||
message to list subscribers.
|
||||
|
||||
It is conforming for an implementation to be hard-coded to treat
|
||||
all clients as being insufficiently trusted. In that case, the
|
||||
implementation does nothing more than parse and discard
|
||||
syntactically valid AUTH parameters to the MAIL FROM command and
|
||||
supply AUTH=<> parameters to any servers to which it
|
||||
authenticates using the AUTH extension.
|
||||
|
||||
Examples:
|
||||
C: MAIL FROM:<e=mc2@example.com> AUTH=e+3Dmc2@example.com
|
||||
S: 250 OK
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 5]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
6. Error Codes
|
||||
|
||||
The following error codes may be used to indicate various conditions
|
||||
as described.
|
||||
|
||||
432 A password transition is needed
|
||||
|
||||
This response to the AUTH command indicates that the user needs to
|
||||
transition to the selected authentication mechanism. This typically
|
||||
done by authenticating once using the PLAIN authentication mechanism.
|
||||
|
||||
534 Authentication mechanism is too weak
|
||||
|
||||
This response to the AUTH command indicates that the selected
|
||||
authentication mechanism is weaker than server policy permits for
|
||||
that user.
|
||||
|
||||
538 Encryption required for requested authentication mechanism
|
||||
|
||||
This response to the AUTH command indicates that the selected
|
||||
authentication mechanism may only be used when the underlying SMTP
|
||||
connection is encrypted.
|
||||
|
||||
454 Temporary authentication failure
|
||||
|
||||
This response to the AUTH command indicates that the authentication
|
||||
failed due to a temporary server failure.
|
||||
|
||||
530 Authentication required
|
||||
|
||||
This response may be returned by any command other than AUTH, EHLO,
|
||||
HELO, NOOP, RSET, or QUIT. It indicates that server policy requires
|
||||
authentication in order to perform the requested action.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 6]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
7. Formal Syntax
|
||||
|
||||
The following syntax specification uses the augmented Backus-Naur
|
||||
Form (BNF) notation as specified in [ABNF].
|
||||
|
||||
Except as noted otherwise, all alphabetic characters are case-
|
||||
insensitive. The use of upper or lower case characters to define
|
||||
token strings is for editorial clarity only. Implementations MUST
|
||||
accept these strings in a case-insensitive fashion.
|
||||
|
||||
UPALPHA = %x41-5A ;; Uppercase: A-Z
|
||||
|
||||
LOALPHA = %x61-7A ;; Lowercase: a-z
|
||||
|
||||
ALPHA = UPALPHA / LOALPHA ;; case insensitive
|
||||
|
||||
DIGIT = %x30-39 ;; Digits 0-9
|
||||
|
||||
HEXDIGIT = %x41-46 / DIGIT ;; hexidecimal digit (uppercase)
|
||||
|
||||
hexchar = "+" HEXDIGIT HEXDIGIT
|
||||
|
||||
xchar = %x21-2A / %x2C-3C / %x3E-7E
|
||||
;; US-ASCII except for "+", "=", SPACE and CTL
|
||||
|
||||
xtext = *(xchar / hexchar)
|
||||
|
||||
AUTH_CHAR = ALPHA / DIGIT / "-" / "_"
|
||||
|
||||
auth_type = 1*20AUTH_CHAR
|
||||
|
||||
auth_command = "AUTH" SPACE auth_type [SPACE (base64 / "=")]
|
||||
*(CRLF [base64]) CRLF
|
||||
|
||||
auth_param = "AUTH=" xtext
|
||||
;; The decoded form of the xtext MUST be either
|
||||
;; an addr-spec or the two characters "<>"
|
||||
|
||||
base64 = base64_terminal /
|
||||
( 1*(4base64_CHAR) [base64_terminal] )
|
||||
|
||||
base64_char = UPALPHA / LOALPHA / DIGIT / "+" / "/"
|
||||
;; Case-sensitive
|
||||
|
||||
base64_terminal = (2base64_char "==") / (3base64_char "=")
|
||||
|
||||
continue_req = "334" SPACE [base64] CRLF
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 7]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
CR = %x0C ;; ASCII CR, carriage return
|
||||
|
||||
CRLF = CR LF
|
||||
|
||||
CTL = %x00-1F / %x7F ;; any ASCII control character and DEL
|
||||
|
||||
LF = %x0A ;; ASCII LF, line feed
|
||||
|
||||
SPACE = %x20 ;; ASCII SP, space
|
||||
|
||||
|
||||
|
||||
|
||||
8. References
|
||||
|
||||
[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax
|
||||
Specifications: ABNF", RFC 2234, November 1997.
|
||||
|
||||
[CRAM-MD5] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP
|
||||
AUTHorize Extension for Simple Challenge/Response", RFC
|
||||
2195, September 1997.
|
||||
|
||||
[ESMTP] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D.
|
||||
Crocker, "SMTP Service Extensions", RFC 1869, November
|
||||
1995.
|
||||
|
||||
[ESMTP-DSN] Moore, K, "SMTP Service Extension for Delivery Status
|
||||
Notifications", RFC 1891, January 1996.
|
||||
|
||||
[KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[SASL] Myers, J., "Simple Authentication and Security Layer
|
||||
(SASL)", RFC 2222, October 1997.
|
||||
|
||||
[SUBMIT] Gellens, R. and J. Klensin, "Message Submission", RFC
|
||||
2476, December 1998.
|
||||
|
||||
[RFC821] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC
|
||||
821, August 1982.
|
||||
|
||||
[RFC822] Crocker, D., "Standard for the Format of ARPA Internet
|
||||
Text Messages", STD 11, RFC 822, August 1982.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 8]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
9. Security Considerations
|
||||
|
||||
Security issues are discussed throughout this memo.
|
||||
|
||||
If a client uses this extension to get an encrypted tunnel through an
|
||||
insecure network to a cooperating server, it needs to be configured
|
||||
to never send mail to that server when the connection is not mutually
|
||||
authenticated and encrypted. Otherwise, an attacker could steal the
|
||||
client's mail by hijacking the SMTP connection and either pretending
|
||||
the server does not support the Authentication extension or causing
|
||||
all AUTH commands to fail.
|
||||
|
||||
Before the SASL negotiation has begun, any protocol interactions are
|
||||
performed in the clear and may be modified by an active attacker.
|
||||
For this reason, clients and servers MUST discard any knowledge
|
||||
obtained prior to the start of the SASL negotiation upon completion
|
||||
of a SASL negotiation which results in a security layer.
|
||||
|
||||
This mechanism does not protect the TCP port, so an active attacker
|
||||
may redirect a relay connection attempt to the submission port
|
||||
[SUBMIT]. The AUTH=<> parameter prevents such an attack from causing
|
||||
an relayed message without an envelope authentication to pick up the
|
||||
authentication of the relay client.
|
||||
|
||||
A message submission client may require the user to authenticate
|
||||
whenever a suitable SASL mechanism is advertised. Therefore, it may
|
||||
not be desirable for a submission server [SUBMIT] to advertise a SASL
|
||||
mechanism when use of that mechanism grants the client no benefits
|
||||
over anonymous submission.
|
||||
|
||||
This extension is not intended to replace or be used instead of end-
|
||||
to-end message signature and encryption systems such as S/MIME or
|
||||
PGP. This extension addresses a different problem than end-to-end
|
||||
systems; it has the following key differences:
|
||||
|
||||
(1) it is generally useful only within a trusted enclave
|
||||
|
||||
(2) it protects the entire envelope of a message, not just the
|
||||
message's body.
|
||||
|
||||
(3) it authenticates the message submission, not authorship of the
|
||||
message content
|
||||
|
||||
(4) it can give the sender some assurance the message was
|
||||
delivered to the next hop in the case where the sender
|
||||
mutually authenticates with the next hop and negotiates an
|
||||
appropriate security layer.
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 9]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
Additional security considerations are mentioned in the SASL
|
||||
specification [SASL].
|
||||
|
||||
|
||||
|
||||
10. Author's Address
|
||||
|
||||
John Gardiner Myers
|
||||
Netscape Communications
|
||||
501 East Middlefield Road
|
||||
Mail Stop MV-029
|
||||
Mountain View, CA 94043
|
||||
|
||||
EMail: jgmyers@netscape.com
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 10]
|
||||
|
||||
RFC 2554 SMTP Authentication March 1999
|
||||
|
||||
|
||||
11. Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (1999). All Rights Reserved.
|
||||
|
||||
This document and translations of it may be copied and furnished to
|
||||
others, and derivative works that comment on or otherwise explain it
|
||||
or assist in its implementation may be prepared, copied, published
|
||||
and distributed, in whole or in part, without restriction of any
|
||||
kind, provided that the above copyright notice and this paragraph are
|
||||
included on all such copies and derivative works. However, this
|
||||
document itself may not be modified in any way, such as by removing
|
||||
the copyright notice or references to the Internet Society or other
|
||||
Internet organizations, except as needed for the purpose of
|
||||
developing Internet standards in which case the procedures for
|
||||
copyrights defined in the Internet Standards process must be
|
||||
followed, or as required to translate it into languages other than
|
||||
English.
|
||||
|
||||
The limited permissions granted above are perpetual and will not be
|
||||
revoked by the Internet Society or its successors or assigns.
|
||||
|
||||
This document and the information contained herein is provided on an
|
||||
"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
||||
TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
||||
BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
||||
HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Myers Standards Track [Page 11]
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,507 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group K. Zeilenga, Ed.
|
||||
Request for Comments: 4505 OpenLDAP Foundation
|
||||
Obsoletes: 2245 June 2006
|
||||
Category: Standards Track
|
||||
|
||||
|
||||
Anonymous Simple Authentication and Security Layer (SASL) Mechanism
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2006).
|
||||
|
||||
Abstract
|
||||
|
||||
On the Internet, it is common practice to permit anonymous access to
|
||||
various services. Traditionally, this has been done with a plain-
|
||||
text password mechanism using "anonymous" as the user name and using
|
||||
optional trace information, such as an email address, as the
|
||||
password. As plain-text login commands are not permitted in new IETF
|
||||
protocols, a new way to provide anonymous login is needed within the
|
||||
context of the Simple Authentication and Security Layer (SASL)
|
||||
framework.
|
||||
|
||||
1. Introduction
|
||||
|
||||
This document defines an anonymous mechanism for the Simple
|
||||
Authentication and Security Layer ([SASL]) framework. The name
|
||||
associated with this mechanism is "ANONYMOUS".
|
||||
|
||||
Unlike many other SASL mechanisms, whose purpose is to authenticate
|
||||
and identify the user to a server, the purpose of this SASL mechanism
|
||||
is to allow the user to gain access to services or resources without
|
||||
requiring the user to establish or otherwise disclose their identity
|
||||
to the server. That is, this mechanism provides an anonymous login
|
||||
method.
|
||||
|
||||
This mechanism does not provide a security layer.
|
||||
|
||||
This document replaces RFC 2245. Changes since RFC 2245 are detailed
|
||||
in Appendix A.
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 1]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
2. The Anonymous Mechanism
|
||||
|
||||
The mechanism consists of a single message from the client to the
|
||||
server. The client may include in this message trace information in
|
||||
the form of a string of [UTF-8]-encoded [Unicode] characters prepared
|
||||
in accordance with [StringPrep] and the "trace" stringprep profile
|
||||
defined in Section 3 of this document. The trace information, which
|
||||
has no semantical value, should take one of two forms: an Internet
|
||||
email address, or an opaque string that does not contain the '@'
|
||||
(U+0040) character and that can be interpreted by the system
|
||||
administrator of the client's domain. For privacy reasons, an
|
||||
Internet email address or other information identifying the user
|
||||
should only be used with permission from the user.
|
||||
|
||||
A server that permits anonymous access will announce support for the
|
||||
ANONYMOUS mechanism and allow anyone to log in using that mechanism,
|
||||
usually with restricted access.
|
||||
|
||||
A formal grammar for the client message using Augmented BNF [ABNF] is
|
||||
provided below as a tool for understanding this technical
|
||||
specification.
|
||||
|
||||
message = [ email / token ]
|
||||
;; to be prepared in accordance with Section 3
|
||||
|
||||
UTF1 = %x00-3F / %x41-7F ;; less '@' (U+0040)
|
||||
UTF2 = %xC2-DF UTF0
|
||||
UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
|
||||
%xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
|
||||
UTF4 = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
|
||||
%xF4 %x80-8F 2(UTF0)
|
||||
UTF0 = %x80-BF
|
||||
|
||||
TCHAR = UTF1 / UTF2 / UTF3 / UTF4
|
||||
;; any UTF-8 encoded Unicode character
|
||||
;; except '@' (U+0040)
|
||||
|
||||
email = addr-spec
|
||||
;; as defined in [IMAIL]
|
||||
|
||||
token = 1*255TCHAR
|
||||
|
||||
Note to implementors:
|
||||
The <token> production is restricted to 255 UTF-8-encoded Unicode
|
||||
characters. As the encoding of a characters uses a sequence of 1
|
||||
to 4 octets, a token may be as long as 1020 octets.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 2]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
3. The "trace" Profile of "Stringprep"
|
||||
|
||||
This section defines the "trace" profile of [StringPrep]. This
|
||||
profile is designed for use with the SASL ANONYMOUS Mechanism.
|
||||
Specifically, the client is to prepare the <message> production in
|
||||
accordance with this profile.
|
||||
|
||||
The character repertoire of this profile is Unicode 3.2 [Unicode].
|
||||
|
||||
No mapping is required by this profile.
|
||||
|
||||
No Unicode normalization is required by this profile.
|
||||
|
||||
The list of unassigned code points for this profile is that provided
|
||||
in Appendix A of [StringPrep]. Unassigned code points are not
|
||||
prohibited.
|
||||
|
||||
Characters from the following tables of [StringPrep] are prohibited:
|
||||
|
||||
- C.2.1 (ASCII control characters)
|
||||
- C.2.2 (Non-ASCII control characters)
|
||||
- C.3 (Private use characters)
|
||||
- C.4 (Non-character code points)
|
||||
- C.5 (Surrogate codes)
|
||||
- C.6 (Inappropriate for plain text)
|
||||
- C.8 (Change display properties are deprecated)
|
||||
- C.9 (Tagging characters)
|
||||
|
||||
No additional characters are prohibited.
|
||||
|
||||
This profile requires bidirectional character checking per Section 6
|
||||
of [StringPrep].
|
||||
|
||||
4. Example
|
||||
|
||||
Here is a sample ANONYMOUS login between an IMAP client and server.
|
||||
In this example, "C:" and "S:" indicate lines sent by the client and
|
||||
server, respectively. If such lines are wrapped without a new "C:"
|
||||
or "S:" label, then the wrapping is for editorial clarity and is not
|
||||
part of the command.
|
||||
|
||||
Note that this example uses the IMAP profile [IMAP4] of SASL. The
|
||||
base64 encoding of challenges and responses as well as the "+ "
|
||||
preceding the responses are part of the IMAP4 profile, not part of
|
||||
SASL itself. Additionally, protocols with SASL profiles permitting
|
||||
an initial client response will be able to avoid the extra round trip
|
||||
below (the server response with an empty "+ ").
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 3]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
In this example, the trace information is "sirhc".
|
||||
|
||||
S: * OK IMAP4 server ready
|
||||
C: A001 CAPABILITY
|
||||
S: * CAPABILITY IMAP4 IMAP4rev1 AUTH=DIGEST-MD5 AUTH=ANONYMOUS
|
||||
S: A001 OK done
|
||||
C: A002 AUTHENTICATE ANONYMOUS
|
||||
S: +
|
||||
C: c2lyaGM=
|
||||
S: A003 OK Welcome, trace information has been logged.
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
The ANONYMOUS mechanism grants access to services and/or resources by
|
||||
anyone. For this reason, it should be disabled by default so that
|
||||
the administrator can make an explicit decision to enable it.
|
||||
|
||||
If the anonymous user has any write privileges, a denial-of-service
|
||||
attack is possible by filling up all available space. This can be
|
||||
prevented by disabling all write access by anonymous users.
|
||||
|
||||
If anonymous users have read and write access to the same area, the
|
||||
server can be used as a communication mechanism to exchange
|
||||
information anonymously. Servers that accept anonymous submissions
|
||||
should implement the common "drop box" model, which forbids anonymous
|
||||
read access to the area where anonymous submissions are accepted.
|
||||
|
||||
If the anonymous user can run many expensive operations (e.g., an
|
||||
IMAP SEARCH BODY command), this could enable a denial-of-service
|
||||
attack. Servers are encouraged to reduce the priority of anonymous
|
||||
users or limit their resource usage.
|
||||
|
||||
While servers may impose a limit on the number of anonymous users,
|
||||
note that such limits enable denial-of-service attacks and should be
|
||||
used with caution.
|
||||
|
||||
The trace information is not authenticated, so it can be falsified.
|
||||
This can be used as an attempt to get someone else in trouble for
|
||||
access to questionable information. Administrators investigating
|
||||
abuse need to realize that this trace information may be falsified.
|
||||
|
||||
A client that uses the user's correct email address as trace
|
||||
information without explicit permission may violate that user's
|
||||
privacy. Anyone who accesses an anonymous archive on a sensitive
|
||||
subject (e.g., sexual abuse) likely has strong privacy needs.
|
||||
Clients should not send the email address without the explicit
|
||||
permission of the user and should offer the option of supplying no
|
||||
trace information, thus only exposing the source IP address and time.
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 4]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
Anonymous proxy servers could enhance this privacy but would have to
|
||||
consider the resulting potential denial-of-service attacks.
|
||||
|
||||
Anonymous connections are susceptible to man-in-the-middle attacks
|
||||
that view or alter the data transferred. Clients and servers are
|
||||
encouraged to support external data security services.
|
||||
|
||||
Protocols that fail to require an explicit anonymous login are more
|
||||
susceptible to break-ins given certain common implementation
|
||||
techniques. Specifically, Unix servers that offer user login may
|
||||
initially start up as root and switch to the appropriate user id
|
||||
after an explicit login command. Normally, such servers refuse all
|
||||
data access commands prior to explicit login and may enter a
|
||||
restricted security environment (e.g., the Unix chroot(2) function)
|
||||
for anonymous users. If anonymous access is not explicitly
|
||||
requested, the entire data access machinery is exposed to external
|
||||
security attacks without the chance for explicit protective measures.
|
||||
Protocols that offer restricted data access should not allow
|
||||
anonymous data access without an explicit login step.
|
||||
|
||||
General [SASL] security considerations apply to this mechanism.
|
||||
|
||||
[StringPrep] security considerations and [Unicode] security
|
||||
considerations discussed in [StringPrep] apply to this mechanism.
|
||||
[UTF-8] security considerations also apply.
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
The SASL Mechanism registry [IANA-SASL] entry for the ANONYMOUS
|
||||
mechanism has been updated by the IANA to reflect that this document
|
||||
now provides its technical specification.
|
||||
|
||||
To: iana@iana.org
|
||||
Subject: Updated Registration of SASL mechanism ANONYMOUS
|
||||
|
||||
SASL mechanism name: ANONYMOUS
|
||||
Security considerations: See RFC 4505.
|
||||
Published specification (optional, recommended): RFC 4505
|
||||
Person & email address to contact for further information:
|
||||
Kurt Zeilenga <Kurt@OpenLDAP.org>
|
||||
Chris Newman <Chris.Newman@sun.com>
|
||||
Intended usage: COMMON
|
||||
Author/Change controller: IESG <iesg@ietf.org>
|
||||
Note: Updates existing entry for ANONYMOUS
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 5]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
The [StringPrep] profile "trace", first defined in this RFC, has been
|
||||
registered:
|
||||
|
||||
To: iana@iana.org
|
||||
Subject: Initial Registration of Stringprep "trace" profile
|
||||
|
||||
Stringprep profile: trace
|
||||
Published specification: RFC 4505
|
||||
Person & email address to contact for further information:
|
||||
Kurt Zeilenga <kurt@openldap.org>
|
||||
|
||||
7. Acknowledgement
|
||||
|
||||
This document is a revision of RFC 2245 by Chris Newman. Portions of
|
||||
the grammar defined in Section 1 were borrowed from RFC 3629 by
|
||||
Francois Yergeau.
|
||||
|
||||
This document is a product of the IETF SASL WG.
|
||||
|
||||
8. Normative References
|
||||
|
||||
[ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax
|
||||
Specifications: ABNF", RFC 4234, October 2005.
|
||||
|
||||
[IMAIL] Resnick, P., "Internet Message Format", RFC 2822, April
|
||||
2001.
|
||||
|
||||
[SASL] Melnikov, A., Ed. and K. Zeilenga, Ed., "Simple
|
||||
Authentication and Security Layer (SASL)", RFC 4422,
|
||||
June 2006.
|
||||
|
||||
[StringPrep] Hoffman, P. and M. Blanchet, "Preparation of
|
||||
Internationalized Strings ('stringprep')", RFC 3454,
|
||||
December 2002.
|
||||
|
||||
[Unicode] The Unicode Consortium, "The Unicode Standard, Version
|
||||
3.2.0" is defined by "The Unicode Standard, Version 3.0"
|
||||
(Reading, MA, Addison-Wesley, 2000. ISBN 0-201-61633-5),
|
||||
as amended by the "Unicode Standard Annex #27: Unicode
|
||||
3.1" (http://www.unicode.org/reports/tr27/) and by the
|
||||
"Unicode Standard Annex #28: Unicode 3.2"
|
||||
(http://www.unicode.org/reports/tr28/).
|
||||
|
||||
[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO
|
||||
10646", RFC 3629 (also STD 63), November 2003.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 6]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
9. Informative References
|
||||
|
||||
[IMAP4] Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
|
||||
4rev1", RFC 3501, March 2003.
|
||||
|
||||
[IANA-SASL] IANA, "SIMPLE AUTHENTICATION AND SECURITY LAYER (SASL)
|
||||
MECHANISMS", <http://www.iana.org/assignments/sasl-
|
||||
mechanisms>.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 7]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
Appendix A. Changes since RFC 2245
|
||||
|
||||
This appendix is non-normative.
|
||||
|
||||
RFC 2245 allows the client to include optional trace information in
|
||||
the form of a human readable string. RFC 2245 restricted this string
|
||||
to US-ASCII. As the Internet is international, this document uses a
|
||||
string restricted to UTF-8 encoded Unicode characters. A
|
||||
"stringprep" profile is defined to precisely define which Unicode
|
||||
characters are allowed in this string. While the string remains
|
||||
restricted to 255 characters, the encoded length of each character
|
||||
may now range from 1 to 4 octets.
|
||||
|
||||
Additionally, a number of editorial changes were made.
|
||||
|
||||
Editor's Address
|
||||
|
||||
Kurt D. Zeilenga
|
||||
OpenLDAP Foundation
|
||||
|
||||
EMail: Kurt@OpenLDAP.org
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 8]
|
||||
|
||||
RFC 4505 Anonymous SASL Mechanism June 2006
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2006).
|
||||
|
||||
This document is subject to the rights, licenses and restrictions
|
||||
contained in BCP 78, and except as set forth therein, the authors
|
||||
retain all their rights.
|
||||
|
||||
This document and the information contained herein are provided on an
|
||||
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
|
||||
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
|
||||
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
|
||||
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
Intellectual Property
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
Intellectual Property Rights or other rights that might be claimed to
|
||||
pertain to the implementation or use of the technology described in
|
||||
this document or the extent to which any license under such rights
|
||||
might or might not be available; nor does it represent that it has
|
||||
made any independent effort to identify any such rights. Information
|
||||
on the procedures with respect to rights in RFC documents can be
|
||||
found in BCP 78 and BCP 79.
|
||||
|
||||
Copies of IPR disclosures made to the IETF Secretariat and any
|
||||
assurances of licenses to be made available, or the result of an
|
||||
attempt made to obtain a general license or permission for the use of
|
||||
such proprietary rights by implementers or users of this
|
||||
specification can be obtained from the IETF on-line IPR repository at
|
||||
http://www.ietf.org/ipr.
|
||||
|
||||
The IETF invites any interested party to bring to its attention any
|
||||
copyrights, patents or patent applications, or other proprietary
|
||||
rights that may cover technology that may be required to implement
|
||||
this standard. Please address the information to the IETF at
|
||||
ietf-ipr@ietf.org.
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is provided by the IETF
|
||||
Administrative Support Activity (IASA).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 9]
|
||||
|
|
@ -0,0 +1,619 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Network Working Group K. Zeilenga, Ed.
|
||||
Request for Comments: 4616 OpenLDAP Foundation
|
||||
Updates: 2595 August 2006
|
||||
Category: Standards Track
|
||||
|
||||
|
||||
The PLAIN Simple Authentication and Security Layer (SASL) Mechanism
|
||||
|
||||
Status of This Memo
|
||||
|
||||
This document specifies an Internet standards track protocol for the
|
||||
Internet community, and requests discussion and suggestions for
|
||||
improvements. Please refer to the current edition of the "Internet
|
||||
Official Protocol Standards" (STD 1) for the standardization state
|
||||
and status of this protocol. Distribution of this memo is unlimited.
|
||||
|
||||
Copyright Notice
|
||||
|
||||
Copyright (C) The Internet Society (2006).
|
||||
|
||||
Abstract
|
||||
|
||||
This document defines a simple clear-text user/password Simple
|
||||
Authentication and Security Layer (SASL) mechanism called the PLAIN
|
||||
mechanism. The PLAIN mechanism is intended to be used, in
|
||||
combination with data confidentiality services provided by a lower
|
||||
layer, in protocols that lack a simple password authentication
|
||||
command.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 1]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
1. Introduction
|
||||
|
||||
Clear-text, multiple-use passwords are simple, interoperate with
|
||||
almost all existing operating system authentication databases, and
|
||||
are useful for a smooth transition to a more secure password-based
|
||||
authentication mechanism. The drawback is that they are unacceptable
|
||||
for use over network connections where data confidentiality is not
|
||||
ensured.
|
||||
|
||||
This document defines the PLAIN Simple Authentication and Security
|
||||
Layer ([SASL]) mechanism for use in protocols with no clear-text
|
||||
login command (e.g., [ACAP] or [SMTP-AUTH]). This document updates
|
||||
RFC 2595, replacing Section 6. Changes since RFC 2595 are detailed
|
||||
in Appendix A.
|
||||
|
||||
The name associated with this mechanism is "PLAIN".
|
||||
|
||||
The PLAIN SASL mechanism does not provide a security layer.
|
||||
|
||||
The PLAIN mechanism should not be used without adequate data security
|
||||
protection as this mechanism affords no integrity or confidentiality
|
||||
protections itself. The mechanism is intended to be used with data
|
||||
security protections provided by application-layer protocol,
|
||||
generally through its use of Transport Layer Security ([TLS])
|
||||
services.
|
||||
|
||||
By default, implementations SHOULD advertise and make use of the
|
||||
PLAIN mechanism only when adequate data security services are in
|
||||
place. Specifications for IETF protocols that indicate that this
|
||||
mechanism is an applicable authentication mechanism MUST mandate that
|
||||
implementations support an strong data security service, such as TLS.
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
|
||||
"SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
|
||||
document are to be interpreted as described in [Keywords].
|
||||
|
||||
2. PLAIN SASL Mechanism
|
||||
|
||||
The mechanism consists of a single message, a string of [UTF-8]
|
||||
encoded [Unicode] characters, from the client to the server. The
|
||||
client presents the authorization identity (identity to act as),
|
||||
followed by a NUL (U+0000) character, followed by the authentication
|
||||
identity (identity whose password will be used), followed by a NUL
|
||||
(U+0000) character, followed by the clear-text password. As with
|
||||
other SASL mechanisms, the client does not provide an authorization
|
||||
identity when it wishes the server to derive an identity from the
|
||||
credentials and use that as the authorization identity.
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 2]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
The formal grammar for the client message using Augmented BNF [ABNF]
|
||||
follows.
|
||||
|
||||
message = [authzid] UTF8NUL authcid UTF8NUL passwd
|
||||
authcid = 1*SAFE ; MUST accept up to 255 octets
|
||||
authzid = 1*SAFE ; MUST accept up to 255 octets
|
||||
passwd = 1*SAFE ; MUST accept up to 255 octets
|
||||
UTF8NUL = %x00 ; UTF-8 encoded NUL character
|
||||
|
||||
SAFE = UTF1 / UTF2 / UTF3 / UTF4
|
||||
;; any UTF-8 encoded Unicode character except NUL
|
||||
|
||||
UTF1 = %x01-7F ;; except NUL
|
||||
UTF2 = %xC2-DF UTF0
|
||||
UTF3 = %xE0 %xA0-BF UTF0 / %xE1-EC 2(UTF0) /
|
||||
%xED %x80-9F UTF0 / %xEE-EF 2(UTF0)
|
||||
UTF4 = %xF0 %x90-BF 2(UTF0) / %xF1-F3 3(UTF0) /
|
||||
%xF4 %x80-8F 2(UTF0)
|
||||
UTF0 = %x80-BF
|
||||
|
||||
The authorization identity (authzid), authentication identity
|
||||
(authcid), password (passwd), and NUL character deliminators SHALL be
|
||||
transferred as [UTF-8] encoded strings of [Unicode] characters. As
|
||||
the NUL (U+0000) character is used as a deliminator, the NUL (U+0000)
|
||||
character MUST NOT appear in authzid, authcid, or passwd productions.
|
||||
|
||||
The form of the authzid production is specific to the application-
|
||||
level protocol's SASL profile [SASL]. The authcid and passwd
|
||||
productions are form-free. Use of non-visible characters or
|
||||
characters that a user may be unable to enter on some keyboards is
|
||||
discouraged.
|
||||
|
||||
Servers MUST be capable of accepting authzid, authcid, and passwd
|
||||
productions up to and including 255 octets. It is noted that the
|
||||
UTF-8 encoding of a Unicode character may be as long as 4 octets.
|
||||
|
||||
Upon receipt of the message, the server will verify the presented (in
|
||||
the message) authentication identity (authcid) and password (passwd)
|
||||
with the system authentication database, and it will verify that the
|
||||
authentication credentials permit the client to act as the (presented
|
||||
or derived) authorization identity (authzid). If both steps succeed,
|
||||
the user is authenticated.
|
||||
|
||||
The presented authentication identity and password strings, as well
|
||||
as the database authentication identity and password strings, are to
|
||||
be prepared before being used in the verification process. The
|
||||
[SASLPrep] profile of the [StringPrep] algorithm is the RECOMMENDED
|
||||
preparation algorithm. The SASLprep preparation algorithm is
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 3]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
recommended to improve the likelihood that comparisons behave in an
|
||||
expected manner. The SASLprep preparation algorithm is not mandatory
|
||||
so as to allow the server to employ other preparation algorithms
|
||||
(including none) when appropriate. For instance, use of a different
|
||||
preparation algorithm may be necessary for the server to interoperate
|
||||
with an external system.
|
||||
|
||||
When preparing the presented strings using [SASLPrep], the presented
|
||||
strings are to be treated as "query" strings (Section 7 of
|
||||
[StringPrep]) and hence unassigned code points are allowed to appear
|
||||
in their prepared output. When preparing the database strings using
|
||||
[SASLPrep], the database strings are to be treated as "stored"
|
||||
strings (Section 7 of [StringPrep]) and hence unassigned code points
|
||||
are prohibited from appearing in their prepared output.
|
||||
|
||||
Regardless of the preparation algorithm used, if the output of a
|
||||
non-invertible function (e.g., hash) of the expected string is
|
||||
stored, the string MUST be prepared before input to that function.
|
||||
|
||||
Regardless of the preparation algorithm used, if preparation fails or
|
||||
results in an empty string, verification SHALL fail.
|
||||
|
||||
When no authorization identity is provided, the server derives an
|
||||
authorization identity from the prepared representation of the
|
||||
provided authentication identity string. This ensures that the
|
||||
derivation of different representations of the authentication
|
||||
identity produces the same authorization identity.
|
||||
|
||||
The server MAY use the credentials to initialize any new
|
||||
authentication database, such as one suitable for [CRAM-MD5] or
|
||||
[DIGEST-MD5].
|
||||
|
||||
3. Pseudo-Code
|
||||
|
||||
This section provides pseudo-code illustrating the verification
|
||||
process (using hashed passwords and the SASLprep preparation
|
||||
function) discussed above. This section is not definitive.
|
||||
|
||||
boolean Verify(string authzid, string authcid, string passwd) {
|
||||
string pAuthcid = SASLprep(authcid, true); # prepare authcid
|
||||
string pPasswd = SASLprep(passwd, true); # prepare passwd
|
||||
if (pAuthcid == NULL || pPasswd == NULL) {
|
||||
return false; # preparation failed
|
||||
}
|
||||
if (pAuthcid == "" || pPasswd == "") {
|
||||
return false; # empty prepared string
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 4]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
storedHash = FetchPasswordHash(pAuthcid);
|
||||
if (storedHash == NULL || storedHash == "") {
|
||||
return false; # error or unknown authcid
|
||||
}
|
||||
|
||||
if (!Compare(storedHash, Hash(pPasswd))) {
|
||||
return false; # incorrect password
|
||||
}
|
||||
|
||||
if (authzid == NULL ) {
|
||||
authzid = DeriveAuthzid(pAuthcid);
|
||||
if (authzid == NULL || authzid == "") {
|
||||
return false; # could not derive authzid
|
||||
}
|
||||
}
|
||||
|
||||
if (!Authorize(pAuthcid, authzid)) {
|
||||
return false; # not authorized
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
The second parameter of the SASLprep function, when true, indicates
|
||||
that unassigned code points are allowed in the input. When the
|
||||
SASLprep function is called to prepare the password prior to
|
||||
computing the stored hash, the second parameter would be false.
|
||||
|
||||
The second parameter provided to the Authorize function is not
|
||||
prepared by this code. The application-level SASL profile should be
|
||||
consulted to determine what, if any, preparation is necessary.
|
||||
|
||||
Note that the DeriveAuthzid and Authorize functions (whether
|
||||
implemented as one function or two, whether designed in a manner in
|
||||
which these functions or whether the mechanism implementation can be
|
||||
reused elsewhere) require knowledge and understanding of mechanism
|
||||
and the application-level protocol specification and/or
|
||||
implementation details to implement.
|
||||
|
||||
Note that the Authorize function outcome is clearly dependent on
|
||||
details of the local authorization model and policy. Both functions
|
||||
may be dependent on other factors as well.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 5]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
4. Examples
|
||||
|
||||
This section provides examples of PLAIN authentication exchanges.
|
||||
The examples are intended to help the readers understand the above
|
||||
text. The examples are not definitive.
|
||||
|
||||
"C:" and "S:" indicate lines sent by the client and server,
|
||||
respectively. "<NUL>" represents a single NUL (U+0000) character.
|
||||
The Application Configuration Access Protocol ([ACAP]) is used in the
|
||||
examples.
|
||||
|
||||
The first example shows how the PLAIN mechanism might be used for
|
||||
user authentication.
|
||||
|
||||
S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
|
||||
C: a001 STARTTLS
|
||||
S: a001 OK "Begin TLS negotiation now"
|
||||
<TLS negotiation, further commands are under TLS layer>
|
||||
S: * ACAP (SASL "CRAM-MD5" "PLAIN")
|
||||
C: a002 AUTHENTICATE "PLAIN"
|
||||
S: + ""
|
||||
C: {21}
|
||||
C: <NUL>tim<NUL>tanstaaftanstaaf
|
||||
S: a002 OK "Authenticated"
|
||||
|
||||
The second example shows how the PLAIN mechanism might be used to
|
||||
attempt to assume the identity of another user. In this example, the
|
||||
server rejects the request. Also, this example makes use of the
|
||||
protocol optional initial response capability to eliminate a round-
|
||||
trip.
|
||||
|
||||
S: * ACAP (SASL "CRAM-MD5") (STARTTLS)
|
||||
C: a001 STARTTLS
|
||||
S: a001 OK "Begin TLS negotiation now"
|
||||
<TLS negotiation, further commands are under TLS layer>
|
||||
S: * ACAP (SASL "CRAM-MD5" "PLAIN")
|
||||
C: a002 AUTHENTICATE "PLAIN" {20+}
|
||||
C: Ursel<NUL>Kurt<NUL>xipj3plmq
|
||||
S: a002 NO "Not authorized to requested authorization identity"
|
||||
|
||||
5. Security Considerations
|
||||
|
||||
As the PLAIN mechanism itself provided no integrity or
|
||||
confidentiality protections, it should not be used without adequate
|
||||
external data security protection, such as TLS services provided by
|
||||
many application-layer protocols. By default, implementations SHOULD
|
||||
NOT advertise and SHOULD NOT make use of the PLAIN mechanism unless
|
||||
adequate data security services are in place.
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 6]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
When the PLAIN mechanism is used, the server gains the ability to
|
||||
impersonate the user to all services with the same password
|
||||
regardless of any encryption provided by TLS or other confidentiality
|
||||
protection mechanisms. Whereas many other authentication mechanisms
|
||||
have similar weaknesses, stronger SASL mechanisms address this issue.
|
||||
Clients are encouraged to have an operational mode where all
|
||||
mechanisms that are likely to reveal the user's password to the
|
||||
server are disabled.
|
||||
|
||||
General [SASL] security considerations apply to this mechanism.
|
||||
|
||||
Unicode, [UTF-8], and [StringPrep] security considerations also
|
||||
apply.
|
||||
|
||||
6. IANA Considerations
|
||||
|
||||
The SASL Mechanism registry [IANA-SASL] entry for the PLAIN mechanism
|
||||
has been updated by the IANA to reflect that this document now
|
||||
provides its technical specification.
|
||||
|
||||
To: iana@iana.org
|
||||
Subject: Updated Registration of SASL mechanism PLAIN
|
||||
|
||||
SASL mechanism name: PLAIN
|
||||
Security considerations: See RFC 4616.
|
||||
Published specification (optional, recommended): RFC 4616
|
||||
Person & email address to contact for further information:
|
||||
Kurt Zeilenga <kurt@openldap.org>
|
||||
IETF SASL WG <ietf-sasl@imc.org>
|
||||
Intended usage: COMMON
|
||||
Author/Change controller: IESG <iesg@ietf.org>
|
||||
Note: Updates existing entry for PLAIN
|
||||
|
||||
7. Acknowledgements
|
||||
|
||||
This document is a revision of RFC 2595 by Chris Newman. Portions of
|
||||
the grammar defined in Section 2 were borrowed from [UTF-8] by
|
||||
Francois Yergeau.
|
||||
|
||||
This document is a product of the IETF Simple Authentication and
|
||||
Security Layer (SASL) Working Group.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 7]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
8. Normative References
|
||||
|
||||
[ABNF] Crocker, D., Ed. and P. Overell, "Augmented BNF for
|
||||
Syntax Specifications: ABNF", RFC 4234, October 2005.
|
||||
|
||||
[Keywords] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[SASL] Melnikov, A., Ed., and K. Zeilenga, Ed., "Simple
|
||||
Authentication and Security Layer (SASL)", RFC 4422,
|
||||
June 2006.
|
||||
|
||||
[SASLPrep] Zeilenga, K., "SASLprep: Stringprep Profile for User
|
||||
Names and Passwords", RFC 4013, February 2005.
|
||||
|
||||
[StringPrep] Hoffman, P. and M. Blanchet, "Preparation of
|
||||
Internationalized Strings ("stringprep")", RFC 3454,
|
||||
December 2002.
|
||||
|
||||
[Unicode] The Unicode Consortium, "The Unicode Standard, Version
|
||||
3.2.0" is defined by "The Unicode Standard, Version
|
||||
3.0" (Reading, MA, Addison-Wesley, 2000. ISBN 0-201-
|
||||
61633-5), as amended by the "Unicode Standard Annex
|
||||
#27: Unicode 3.1"
|
||||
(http://www.unicode.org/reports/tr27/) and by the
|
||||
"Unicode Standard Annex #28: Unicode 3.2"
|
||||
(http://www.unicode.org/reports/tr28/).
|
||||
|
||||
[UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO
|
||||
10646", STD 63, RFC 3629, November 2003.
|
||||
|
||||
[TLS] Dierks, T. and E. Rescorla, "The Transport Layer
|
||||
Security (TLS) Protocol Version 1.1", RFC 4346, April
|
||||
2006.
|
||||
|
||||
9. Informative References
|
||||
|
||||
[ACAP] Newman, C. and J. Myers, "ACAP -- Application
|
||||
Configuration Access Protocol", RFC 2244, November
|
||||
1997.
|
||||
|
||||
[CRAM-MD5] Nerenberg, L., Ed., "The CRAM-MD5 SASL Mechanism", Work
|
||||
in Progress, June 2006.
|
||||
|
||||
[DIGEST-MD5] Melnikov, A., Ed., "Using Digest Authentication as a
|
||||
SASL Mechanism", Work in Progress, June 2006.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 8]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
[IANA-SASL] IANA, "SIMPLE AUTHENTICATION AND SECURITY LAYER (SASL)
|
||||
MECHANISMS",
|
||||
<http://www.iana.org/assignments/sasl-mechanisms>.
|
||||
|
||||
[SMTP-AUTH] Myers, J., "SMTP Service Extension for Authentication",
|
||||
RFC 2554, March 1999.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 9]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
Appendix A. Changes since RFC 2595
|
||||
|
||||
This appendix is non-normative.
|
||||
|
||||
This document replaces Section 6 of RFC 2595.
|
||||
|
||||
The specification details how the server is to compare client-
|
||||
provided character strings with stored character strings.
|
||||
|
||||
The ABNF grammar was updated. In particular, the grammar now allows
|
||||
LINE FEED (U+000A) and CARRIAGE RETURN (U+000D) characters in the
|
||||
authzid, authcid, passwd productions. However, whether these control
|
||||
characters may be used depends on the string preparation rules
|
||||
applicable to the production. For passwd and authcid productions,
|
||||
control characters are prohibited. For authzid, one must consult the
|
||||
application-level SASL profile. This change allows PLAIN to carry
|
||||
all possible authorization identity strings allowed in SASL.
|
||||
|
||||
Pseudo-code was added.
|
||||
|
||||
The example section was expanded to illustrate more features of the
|
||||
PLAIN mechanism.
|
||||
|
||||
Editor's Address
|
||||
|
||||
Kurt D. Zeilenga
|
||||
OpenLDAP Foundation
|
||||
|
||||
EMail: Kurt@OpenLDAP.org
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 10]
|
||||
|
||||
RFC 4616 The PLAIN SASL Mechanism August 2006
|
||||
|
||||
|
||||
Full Copyright Statement
|
||||
|
||||
Copyright (C) The Internet Society (2006).
|
||||
|
||||
This document is subject to the rights, licenses and restrictions
|
||||
contained in BCP 78, and except as set forth therein, the authors
|
||||
retain all their rights.
|
||||
|
||||
This document and the information contained herein are provided on an
|
||||
"AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
|
||||
OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
|
||||
ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
|
||||
INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
Intellectual Property
|
||||
|
||||
The IETF takes no position regarding the validity or scope of any
|
||||
Intellectual Property Rights or other rights that might be claimed to
|
||||
pertain to the implementation or use of the technology described in
|
||||
this document or the extent to which any license under such rights
|
||||
might or might not be available; nor does it represent that it has
|
||||
made any independent effort to identify any such rights. Information
|
||||
on the procedures with respect to rights in RFC documents can be
|
||||
found in BCP 78 and BCP 79.
|
||||
|
||||
Copies of IPR disclosures made to the IETF Secretariat and any
|
||||
assurances of licenses to be made available, or the result of an
|
||||
attempt made to obtain a general license or permission for the use of
|
||||
such proprietary rights by implementers or users of this
|
||||
specification can be obtained from the IETF on-line IPR repository at
|
||||
http://www.ietf.org/ipr.
|
||||
|
||||
The IETF invites any interested party to bring to its attention any
|
||||
copyrights, patents or patent applications, or other proprietary
|
||||
rights that may cover technology that may be required to implement
|
||||
this standard. Please address the information to the IETF at
|
||||
ietf-ipr@ietf.org.
|
||||
|
||||
Acknowledgement
|
||||
|
||||
Funding for the RFC Editor function is provided by the IETF
|
||||
Administrative Support Activity (IASA).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Zeilenga Standards Track [Page 11]
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,61 @@
|
|||
RFC 1854:
|
||||
---------
|
||||
PIPELINING extension
|
||||
|
||||
RFC 2222:
|
||||
---------
|
||||
SASL
|
||||
|
||||
RFC 4505:
|
||||
---------
|
||||
ANYNONYMOUS SASL
|
||||
|
||||
RFC 4616:
|
||||
---------
|
||||
PLAIN SASL
|
||||
|
||||
RFC 2487:
|
||||
---------
|
||||
STARTTLS extension
|
||||
|
||||
RFC 2554 & 4954:
|
||||
----------------
|
||||
AUTH extension
|
||||
|
||||
RFC 2821:
|
||||
---------
|
||||
SMTP protocol
|
||||
|
||||
RFC 2822:
|
||||
---------
|
||||
General message structure (focusing on important headers)
|
||||
|
||||
RFC 2045:
|
||||
---------
|
||||
Quoted Printable Encoding
|
||||
Base 64 Encoding
|
||||
Detailed message structure
|
||||
|
||||
RFC 2046:
|
||||
---------
|
||||
Media types (for subparts)
|
||||
|
||||
RFC 2047:
|
||||
---------
|
||||
Header Encoding
|
||||
|
||||
RFC 2183:
|
||||
---------
|
||||
The Content-Disposition header
|
||||
|
||||
RFC 2231:
|
||||
---------
|
||||
Encoded Text header/attribute extensions
|
||||
|
||||
RFC 2234:
|
||||
---------
|
||||
ABNF definitions
|
||||
|
||||
RFC 3676:
|
||||
---------
|
||||
Flowed formatting/delsp parameters
|
|
@ -0,0 +1,48 @@
|
|||
General Notes
|
||||
--------------
|
||||
* MX is NOT required, but an A record, or CNAME to a MX MUST be present at the least.
|
||||
* EHLO should be tried, then fall back to HELO
|
||||
* The 250 return code from RCPT TO is not actually clear-cut. A 251 may be
|
||||
returned if the message was forwarded to another address. This could be a
|
||||
useful indicator to end-users that an address should be updated.
|
||||
* RCPT TO can accpet just "postmaster" without a domain name
|
||||
* Server MUST not close connection before:
|
||||
- QUIT and returning 221 response
|
||||
- Forced requirement, and only after returning a 421 response
|
||||
- Clients expriencing a forced connection closure, without prior warning should
|
||||
just treat it like a 451 closure regardless
|
||||
* ALWAYS use blocking sockets for the initial connection (this should prevent
|
||||
Exim4's whining about sync).
|
||||
|
||||
Response codes
|
||||
--------------
|
||||
* From RFC2821, 4.2.
|
||||
- In particular, the 220, 221, 251, 421, and 551 reply codes
|
||||
are associated with message text that must be parsed and interpreted
|
||||
by machines.
|
||||
|
||||
Error Codes
|
||||
------------
|
||||
* Numeric 5yz = Error
|
||||
- 550/RCPT TO = Relay denied
|
||||
- 500 = Unknown command
|
||||
* Numeric 2yz = Normal
|
||||
* Numeric 4yz = Temporary failure??
|
||||
|
||||
<?php
|
||||
|
||||
class EsmtpTransport implements Transport, EsmtpCommandWriter {
|
||||
}
|
||||
|
||||
interface EsmtpCommandWriter {
|
||||
public function getBuffer();
|
||||
public function executeCommand($command, $expectedCodes);
|
||||
}
|
||||
|
||||
interface Extension {
|
||||
public function getKeyword();
|
||||
public function afterEhlo($commandWriter);
|
||||
public function getRcptParams();
|
||||
public function getMailParams();
|
||||
public function atCommand($commandWriter, $command, $expectedResponse) throws CommandSentException;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<package packagerversion="1.8.0" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
|
||||
http://pear.php.net/dtd/tasks-1.0.xsd
|
||||
http://pear.php.net/dtd/package-2.0
|
||||
http://pear.php.net/dtd/package-2.0.xsd">
|
||||
<name>Swift</name>
|
||||
<channel>pear.swiftmailer.org</channel>
|
||||
<summary>Free Feature-rich PHP Mailer.</summary>
|
||||
<description>
|
||||
Swift Mailer integrates into any web app written in PHP 5, offering a flexible and elegant object-oriented approach to sending emails with a multitude of features.
|
||||
</description>
|
||||
<lead>
|
||||
<name>Fabien Potencier</name>
|
||||
<user>fabpot</user>
|
||||
<email>fabien.potencier@symfony-project.org</email>
|
||||
<active>yes</active>
|
||||
</lead>
|
||||
<lead>
|
||||
<name>Chris Corbyn</name>
|
||||
<user>d11wtq</user>
|
||||
<email></email>
|
||||
<active>no</active>
|
||||
</lead>
|
||||
<date>{{ date }}</date>
|
||||
<time>{{ time }}</time>
|
||||
<version>
|
||||
<release>{{ version }}</release>
|
||||
<api>{{ api_version }}</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>{{ stability }}</release>
|
||||
<api>{{ stability }}</api>
|
||||
</stability>
|
||||
<license uri="http://www.opensource.org/licenses/lgpl-3.0.html">LGPL</license>
|
||||
<notes>-</notes>
|
||||
<contents>
|
||||
<dir name="/">
|
||||
<file name="CHANGES" role="doc" />
|
||||
<file name="LICENSE" role="doc" />
|
||||
<file name="README" role="doc" />
|
||||
<file name="VERSION" role="doc" />
|
||||
<dir name="lib">
|
||||
<file install-as="mime_types.php" name="mime_types.php" role="php" />
|
||||
<file install-as="preferences.php" name="preferences.php" role="php" />
|
||||
<file install-as="swift_init.php" name="swift_init.php" role="php" />
|
||||
<file install-as="swift_required.php" name="swift_required_pear.php" role="php" />
|
||||
<dir name="dependency_maps">
|
||||
<file install-as="dependency_maps/cache_deps.php" name="cache_deps.php" role="php" />
|
||||
<file install-as="dependency_maps/mime_deps.php" name="mime_deps.php" role="php" />
|
||||
<file install-as="dependency_maps/transport_deps.php" name="transport_deps.php" role="php" />
|
||||
<file install-as="dependency_maps/message_deps.php" name="message_deps.php" role="php" />
|
||||
</dir>
|
||||
<dir name="classes">
|
||||
<file install-as="Swift.php" name="Swift.php" role="php" />
|
||||
<dir name="Swift">
|
||||
{{ files }}
|
||||
</dir>
|
||||
</dir>
|
||||
</dir>
|
||||
</dir>
|
||||
</contents>
|
||||
<dependencies>
|
||||
<required>
|
||||
<php>
|
||||
<min>5.2.4</min>
|
||||
</php>
|
||||
<pearinstaller>
|
||||
<min>1.4.0</min>
|
||||
</pearinstaller>
|
||||
</required>
|
||||
</dependencies>
|
||||
<phprelease />
|
||||
</package>
|
|
@ -0,0 +1,7 @@
|
|||
Sweety SimpleTest Front-end, Version 0.1 - beta
|
||||
-----------------------------------------------
|
||||
|
||||
17th November 2007, 0.1b:
|
||||
Finished initial draft, giving up on dealing with invalid XML for now since
|
||||
$test->dump() should be used for output where needed. Will address this again
|
||||
later.
|
|
@ -0,0 +1,165 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
|
@ -0,0 +1,159 @@
|
|||
Sweety SimpleTest Suite
|
||||
-----------------------
|
||||
|
||||
Sweety is a wrapper around SimpleTest's XML reporting capabilities which
|
||||
makes unit tests easier to manage and friendlier to run.
|
||||
|
||||
Tests are run in a grouped fashion, but each individual test runs in its own
|
||||
environment and own memory space either via forking new PHP processes, or by
|
||||
making new HTTP requests.
|
||||
|
||||
Sweety works with any vanilla version of SimpleTest since the XmlReporter was
|
||||
added.
|
||||
|
||||
Tests can be run on command line, in an AJAX equipped web browser*, or in a
|
||||
web browser with javascript turned off.
|
||||
|
||||
* Sweety has been tested with success in the following browsers:
|
||||
|
||||
- Mozilla Firefox 2.0
|
||||
- Safari 3-beta
|
||||
- Internet Explorer 7
|
||||
- Opera 9
|
||||
|
||||
|
||||
Configuring Sweety:
|
||||
--------------------
|
||||
|
||||
All Sweety configuration is contained inside the config.php file, defined as
|
||||
constants for the mostpart.
|
||||
|
||||
Make sure you at least indicate a path to a directory containing SimpleTest,
|
||||
and also change the SWEETY_INCLUDE_PATH and SWEETY_TEST_PATH to fit your needs.
|
||||
|
||||
Paths are provided using the directory separator for your OS. Use the PHP
|
||||
constant PATH_SEPARATOR if you need to run in different environments.
|
||||
|
||||
If you have test cases in directories /webdev/tests/unit and
|
||||
/webdev/tests/integration your SWEETY_TEST_PATH should look like:
|
||||
|
||||
define('SWEETY_TEST_PATH', '/webdev/tests/unit' . PATH_SEPARATOR .
|
||||
'/webdev/tests/integration');
|
||||
|
||||
If you want to run Sweety on the command line you'll need to specify the path
|
||||
to your PHP executable (typically /usr/bin/php). Sweety needs to be able to
|
||||
fork new processes using this executable.
|
||||
|
||||
|
||||
What to do if your naming scheme doesn't use PEAR conventions:
|
||||
--------------------------------------------------------------
|
||||
|
||||
By default Sweety looks for classes using PEAR naming conventions. If you use
|
||||
some other naming convention you need to tell Sweety how to find your test cases.
|
||||
|
||||
This is a two step process:
|
||||
|
||||
1) Write a new Sweety_TestLocator -- don't worry, it's easy!
|
||||
|
||||
Refer to the interface in lib/Sweety/TestLocator.php for guidance on what
|
||||
your TestLocator needs to include (just two methods for searching and including).
|
||||
|
||||
2) Add it to your config.php.
|
||||
|
||||
Once you've written a new TestLocator which works for your naming scheme,
|
||||
change the config value SWEETY_TEST_LOCATOR to the name of your new class, then
|
||||
include the class file somewhere inside the config.php. If you use multiple class
|
||||
naming conventions, list your TestLocators as a comma separated string.
|
||||
|
||||
|
||||
Making tests appear in Sweety's interface:
|
||||
-------------------------------------------
|
||||
|
||||
No really, you just edit the configuration and they'll show up if a TestLocator
|
||||
can find them ;)
|
||||
|
||||
|
||||
Running sweety on the command line:
|
||||
-----------------------------------
|
||||
|
||||
Interacting with Sweety on the command line you'll get almost as much detail
|
||||
as you do in a web browser, although the formatting obviously isn't so pretty!
|
||||
|
||||
All operations are handled by the file named run.php in the sweety installation
|
||||
directory.
|
||||
|
||||
-bash$ php run.php #runs all tests
|
||||
-bash$ php run.php Name_Of_TestClass #runs a single test case
|
||||
-bash$ php run.php Name_Of_TestClass xml #runs a single test case in XML
|
||||
|
||||
|
||||
|
||||
Runing Sweety with AJAX:
|
||||
-------------------------
|
||||
|
||||
Open up an AJAX equipped web browsers (preferably supporting DOM 3 XPath, but at
|
||||
least support basic DOM). Navigate to the index.php file at the installation
|
||||
directory of Sweety. You'll see the screen is divided into two sections, left
|
||||
and right. On the left there's a list of test cases which you can click to run.
|
||||
On the right you get all the verbose output from running the tests.
|
||||
|
||||
Clicking the "Run Tests" button will run all tests you can currently see in
|
||||
the list. As each test runs, a request is sent to the web server to get
|
||||
SimpleTest to run your test case. If the test passes the test case will turn
|
||||
green, if it fails it will turn red. Tests go yellow until a final conclusion
|
||||
is drawn.
|
||||
|
||||
If you need to stop the tests at any time just click the button again (it
|
||||
should say "Stop Tests" whilst the tests run).
|
||||
|
||||
Whilst the tests run, the large bar to the right of the screen will tally
|
||||
up aggregated results and will eventually go either green or red indicating
|
||||
a pass or failure. Failed assertion messages will appear in the page just like
|
||||
they do with the HtmlReporter of SimpleTest.
|
||||
|
||||
Clicking a single test case will run just that test in isolation. If you want
|
||||
(or need?) to run the test with SimpleTest's HtmlReporter just click the
|
||||
HTML Icon (little world image) next to the test case. Tests can also be run in
|
||||
XML if needed.
|
||||
|
||||
Above the list of tests there's a filter box which can be directly typed into.
|
||||
Typing in here narrows down the list of testcases to show only the ones which
|
||||
match the search query.
|
||||
|
||||
Refreshing the page with your browser's refresh button will reset the test suite.
|
||||
|
||||
When you change your code, you DO NOT need to refesh your browser window. Just
|
||||
click the "Run Tests" button, or click the individual test to refresh the results.
|
||||
|
||||
If you add a new test case you will need to refresh your browser window however.
|
||||
|
||||
|
||||
Running Sweety without JavaScript:
|
||||
----------------------------------
|
||||
|
||||
If your web browser has JavaScript disabled you can still use the HTML version
|
||||
of the test suite. Open up the index.php file in your web browser.
|
||||
|
||||
You'll see the screen is divided into two sections, left
|
||||
and right. On the left there's a list of test cases with checkboxes next to them
|
||||
which you can check to run. On the right you get all the verbose output from
|
||||
running the tests.
|
||||
|
||||
Clicking the "Run Tests" button will run all the currently selected test cases.
|
||||
This could take a long time depending upon how many tests you have to run,
|
||||
but once complete you'll see the page again where the tests you selected will
|
||||
either be red or green indicating a pass or failure. The bar at the right of
|
||||
the screen will contain aggregate results for all the tests and will be either
|
||||
red or green to indicate an overall pass or failure.
|
||||
|
||||
Assertion messages appear in the page just like with SimpleTest's HtmlReporter.
|
||||
|
||||
If you want to run just a single test case, click the "Run" icon at the right
|
||||
of the test (little running man image).
|
||||
|
||||
You can run tests with SimpleTest's HtmlReporter by clicking the HTML icon
|
||||
(little world image) next to the test case. Tests can be run in XML if needed
|
||||
too.
|
||||
|
||||
Enjoy!
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
//Error reporting settings
|
||||
error_reporting(E_ALL | E_STRICT); ini_set('display_errors', true);
|
||||
|
||||
if (defined('E_DEPRECATED'))
|
||||
{
|
||||
error_reporting(error_reporting() | E_DEPRECATED);
|
||||
}
|
||||
|
||||
//E_STRICT compliance -- If you change this timezone some tests may fail -
|
||||
// This only affects the tests, you need to ensure PHP is correctly set up in
|
||||
// your own code
|
||||
date_default_timezone_set('Australia/ACT');
|
||||
|
||||
//Time limit to process all tests
|
||||
set_time_limit(30);
|
||||
|
||||
//The path to the PHP command line executable (auto-detected if none set)
|
||||
define('SWEETY_PHP_EXE', '');
|
||||
//The path to this file
|
||||
define('SWEETY_HOME', dirname(__FILE__));
|
||||
//The path to the libs being tested
|
||||
define('SWEETY_INCLUDE_PATH',
|
||||
SWEETY_HOME . '/../lib/classes' . PATH_SEPARATOR .
|
||||
SWEETY_HOME . '/../lib' . PATH_SEPARATOR .
|
||||
SWEETY_HOME . '/../tests/helpers'
|
||||
);
|
||||
//The path to the main test suite
|
||||
define('SWEETY_LIB_PATH', SWEETY_HOME . '/lib');
|
||||
//The path to simpletest
|
||||
define('SWEETY_SIMPLETEST_PATH', SWEETY_LIB_PATH . '/simpletest');
|
||||
//The path to any testing directories
|
||||
define('SWEETY_TEST_PATH',
|
||||
SWEETY_HOME . '/../tests/unit' .
|
||||
PATH_SEPARATOR . SWEETY_HOME . '/../tests/acceptance' .
|
||||
PATH_SEPARATOR . SWEETY_HOME . '/../tests/smoke' .
|
||||
PATH_SEPARATOR . SWEETY_HOME . '/../tests/bug'
|
||||
);
|
||||
//Test locator strategies, separated by commas
|
||||
define('SWEETY_TEST_LOCATOR', 'Sweety_TestLocator_PearStyleLocator');
|
||||
//A pattern used for filtering out certain class names expected to be tests
|
||||
define('SWEETY_IGNORED_CLASSES', '/(^|_)Abstract/');
|
||||
//The name which appears at the top of the test suite
|
||||
define('SWEETY_SUITE_NAME', 'Swift Mailer 4 Test Suite');
|
||||
//The path to the template which renders the view
|
||||
define('SWEETY_UI_TEMPLATE', SWEETY_HOME . '/templates/sweety/suite-ui.tpl.php');
|
||||
|
||||
//Most likely you won't want to modify the include_path
|
||||
set_include_path(
|
||||
dirname(__FILE__) . '/../lib' . PATH_SEPARATOR .
|
||||
SWEETY_LIB_PATH . PATH_SEPARATOR .
|
||||
SWEETY_INCLUDE_PATH . PATH_SEPARATOR .
|
||||
SWEETY_TEST_PATH
|
||||
);
|
||||
|
||||
//Load in any dependencies
|
||||
require_once 'Sweety/TestLocator/PearStyleLocator.php';
|
||||
require_once 'swift_required.php';
|
||||
|
||||
//Force init to be required
|
||||
require_once 'swift_init.php';
|
||||
|
||||
//Load in some swift specific testig config
|
||||
require_once SWEETY_HOME . '/../tests/acceptance.conf.php';
|
||||
require_once SWEETY_HOME . '/../tests/smoke.conf.php';
|
||||
require_once SWEETY_HOME . '/lib/yaymock/yay_mock.php';
|
||||
require_once SWEETY_HOME . '/lib/yaymock/yay_convenience.php';
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
require_once dirname(__FILE__) . '/config.php';
|
||||
|
||||
require_once SWEETY_SIMPLETEST_PATH . '/unit_tester.php';
|
||||
require_once SWEETY_SIMPLETEST_PATH . '/mock_objects.php';
|
||||
require_once SWEETY_SIMPLETEST_PATH . '/reporter.php';
|
||||
require_once SWEETY_SIMPLETEST_PATH . '/xml.php';
|
||||
|
||||
require_once 'Sweety/Runner.php';
|
||||
require_once 'Sweety/Runner/HtmlRunner.php';
|
||||
require_once 'Sweety/Reporter/HtmlReporter.php';
|
||||
|
||||
$runner = new Sweety_Runner_HtmlRunner(
|
||||
explode(PATH_SEPARATOR, SWEETY_TEST_PATH),
|
||||
SWEETY_UI_TEMPLATE,
|
||||
SWEETY_SUITE_NAME
|
||||
);
|
||||
|
||||
$runner->setReporter(new Sweety_Reporter_HtmlReporter());
|
||||
|
||||
$runner->setIgnoredClassRegex(SWEETY_IGNORED_CLASSES);
|
||||
|
||||
$locators = preg_split('/\s*,\s*/', SWEETY_TEST_LOCATOR);
|
||||
foreach ($locators as $locator)
|
||||
{
|
||||
$runner->registerTestLocator(new $locator());
|
||||
}
|
||||
|
||||
if (isset($_GET['test']))
|
||||
{
|
||||
$testName = $_GET['test'];
|
||||
$format = isset($_GET['format']) ? $_GET['format'] : Sweety_Runner::REPORT_HTML;
|
||||
|
||||
$runner->runTestCase($testName, $format);
|
||||
}
|
||||
else
|
||||
{
|
||||
$runner->runAllTests();
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Interface for sending output to the client.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
interface Sweety_Reporter
|
||||
{
|
||||
|
||||
/**
|
||||
* Get the reporter used to report on this specific test case.
|
||||
* @param string $testCase
|
||||
* @return Sweety_Reporter
|
||||
*/
|
||||
public function getReporterFor($testCase);
|
||||
|
||||
/**
|
||||
* Returns true if start() has been invoked.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStarted();
|
||||
|
||||
/**
|
||||
* Start reporting.
|
||||
*/
|
||||
public function start();
|
||||
|
||||
/**
|
||||
* Report a skipped test case.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportSkip($message, $path);
|
||||
|
||||
/**
|
||||
* Report a passing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportPass($message, $path);
|
||||
|
||||
/**
|
||||
* Report a failing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportFail($message, $path);
|
||||
|
||||
/**
|
||||
* Report an unexpected exception.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportException($message, $path);
|
||||
|
||||
/**
|
||||
* Report output from something like a dump().
|
||||
* @param string $output
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportOutput($output, $path);
|
||||
|
||||
/**
|
||||
* End reporting.
|
||||
*/
|
||||
public function finish();
|
||||
|
||||
}
|
203
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/CliReporter.php
vendored
Normal file
203
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/CliReporter.php
vendored
Normal file
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/Reporter.php';
|
||||
require_once 'Sweety/Reporter/CliTestCaseReporter.php';
|
||||
|
||||
/**
|
||||
* The reporter used in command line reporting.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Sweety_Reporter_CliReporter implements Sweety_Reporter
|
||||
{
|
||||
|
||||
/**
|
||||
* True if this repoter is running.
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
private $_started = false;
|
||||
|
||||
/**
|
||||
* The name to show this report as.
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $_name;
|
||||
|
||||
/**
|
||||
* Aggregate scores from tests run.
|
||||
* @var int[]
|
||||
*/
|
||||
private $_aggregates = array();
|
||||
|
||||
/**
|
||||
* Creates a new CliReporter.
|
||||
*/
|
||||
public function __construct($name)
|
||||
{
|
||||
$this->_name = $name;
|
||||
$this->_aggregates = array(
|
||||
'cases' => 0,
|
||||
'run' => 0,
|
||||
'passes' => 0,
|
||||
'fails' => 0,
|
||||
'exceptions' => 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used so test case reporters can notify this reporter when they've completed.
|
||||
* @param string $testCase
|
||||
*/
|
||||
public function notifyEnded($testCase)
|
||||
{
|
||||
$this->_aggregates['run']++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reporter used to report on this specific test case.
|
||||
* @param string $testCase
|
||||
* @return Sweety_Reporter
|
||||
*/
|
||||
public function getReporterFor($testCase)
|
||||
{
|
||||
$this->_aggregates['cases']++;
|
||||
|
||||
$reporter = new Sweety_Reporter_CliTestCaseReporter($testCase, $this);
|
||||
return $reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if start() has been invoked.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStarted()
|
||||
{
|
||||
return $this->_started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start reporting.
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
$this->_started = true;
|
||||
echo $this->_name . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a skipped test case.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportSkip($message, $path)
|
||||
{
|
||||
echo " \033[34m\033[1m\033[4mSkip\033[0m:";
|
||||
$messageLines = explode(PHP_EOL, wordwrap($message, 74, PHP_EOL));
|
||||
foreach ($messageLines as $line)
|
||||
{
|
||||
echo ' ' . $line . PHP_EOL;
|
||||
}
|
||||
echo ' in: ' . $path . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a passing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportPass($message, $path)
|
||||
{
|
||||
$this->_aggregates['passes']++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a failing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportFail($message, $path)
|
||||
{
|
||||
$this->_aggregates['fails']++;
|
||||
|
||||
echo "\033[31m" . $this->_aggregates['fails'] . ') ';
|
||||
echo $message . "\033[0m" . PHP_EOL;
|
||||
echo ' in: ' . $path . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an unexpected exception.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportException($message, $path)
|
||||
{
|
||||
$this->_aggregates['exceptions']++;
|
||||
|
||||
echo "\033[31m\033[1mException" . $this->_aggregates['exceptions'] . "\033[0m!" . PHP_EOL;
|
||||
echo "\033[1m" . $message . "\033[0m" . PHP_EOL;
|
||||
echo ' in ' . $path . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report output from something like a dump().
|
||||
* @param string $output
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportOutput($output, $path)
|
||||
{
|
||||
if (preg_match('/^\{image @ (.*?)\}$/D', $output, $matches))
|
||||
{
|
||||
echo " \033[33mSmoke Test\033[0m" . PHP_EOL;
|
||||
echo ' Compare email sent with image @ ' . $matches[1] . PHP_EOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo '--------------------' . PHP_EOL;
|
||||
echo $output . PHP_EOL;
|
||||
echo '--------------------' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* End reporting.
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
$this->_started = false;
|
||||
|
||||
$incomplete = $this->_aggregates['cases'] - $this->_aggregates['run'];
|
||||
|
||||
if ($incomplete)
|
||||
{
|
||||
echo '**********************' . PHP_EOL;
|
||||
echo $incomplete . ' test case(s) did not complete.' . PHP_EOL .
|
||||
'This may be because invalid XML was output during the test run' . PHP_EOL .
|
||||
'and/or because an error occured.' . PHP_EOL .
|
||||
'Try running the tests separately for more detail.' . PHP_EOL;
|
||||
echo '**********************' . PHP_EOL;
|
||||
}
|
||||
|
||||
$success = (!$this->_aggregates['fails'] && !$this->_aggregates['exceptions']
|
||||
&& $this->_aggregates['cases'] == $this->_aggregates['run']);
|
||||
|
||||
if ($success)
|
||||
{
|
||||
echo "\033[32m\033[1mOK\033[0m" . PHP_EOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "\033[31m\033[1mFAILURES!!!\033[0m" . PHP_EOL;
|
||||
}
|
||||
|
||||
echo 'Test cases run: ';
|
||||
echo $this->_aggregates['run'] . '/' . $this->_aggregates['cases'] . ', ';
|
||||
echo 'Passes: ' . $this->_aggregates['passes'] . ', ';
|
||||
echo 'Failures: ' . $this->_aggregates['fails'] . ', ';
|
||||
echo 'Exceptions: '. $this->_aggregates['exceptions'] . PHP_EOL;
|
||||
|
||||
exit((int) !$success);
|
||||
}
|
||||
|
||||
}
|
160
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/CliTestCaseReporter.php
vendored
Normal file
160
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/CliTestCaseReporter.php
vendored
Normal file
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/Reporter.php';
|
||||
require_once 'Sweety/Reporter/CliReporter.php';
|
||||
|
||||
/**
|
||||
* A command line reporter for an individual test case.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Sweety_Reporter_CliTestCaseReporter implements Sweety_Reporter
|
||||
{
|
||||
|
||||
/**
|
||||
* True if this reporter is running.
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
private $_started = false;
|
||||
|
||||
/**
|
||||
* The name of the test case being reported on.
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $_testCase;
|
||||
|
||||
/**
|
||||
* The parent reporter this was spawned from.
|
||||
* @var Sweety_Reporter_CliReporter
|
||||
* @access private
|
||||
*/
|
||||
private $_parent;
|
||||
|
||||
/**
|
||||
* Aggregate totals for this test case.
|
||||
* @var int[]
|
||||
* @access private
|
||||
*/
|
||||
private $_aggregates = array();
|
||||
|
||||
/**
|
||||
* Creates a new CliTestCaseReporter.
|
||||
* @param string $testCase
|
||||
* @param Sweety_Reporter_CliReporter The parent reporter this was spawned from.
|
||||
*/
|
||||
public function __construct($testCase, Sweety_Reporter_CliReporter $parent)
|
||||
{
|
||||
$this->_parent = $parent;
|
||||
$this->_testCase = $testCase;
|
||||
$this->_aggregates = array(
|
||||
'passes' => 0,
|
||||
'fails' => 0,
|
||||
'exceptions' => 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reporter used to report on this specific test case.
|
||||
* This method is stubbed only to return itself.
|
||||
* @param string $testCase
|
||||
* @return Sweety_Reporter
|
||||
*/
|
||||
public function getReporterFor($testCase)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if start() has been invoked.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStarted()
|
||||
{
|
||||
return $this->_started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start reporting.
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
$this->_started = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a skipped test case.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportSkip($message, $path)
|
||||
{
|
||||
$this->_parent->reportSkip($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a passing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportPass($message, $path)
|
||||
{
|
||||
$this->_aggregates['passes']++;
|
||||
$this->_parent->reportPass($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a failing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportFail($message, $path)
|
||||
{
|
||||
$this->_aggregates['fails']++;
|
||||
$this->_parent->reportFail($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an unexpected exception.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportException($message, $path)
|
||||
{
|
||||
$this->_aggregates['exceptions']++;
|
||||
$this->_parent->reportException($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report output from something like a dump().
|
||||
* @param string $output
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportOutput($output, $path)
|
||||
{
|
||||
$this->_parent->reportOutput($output, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* End reporting.
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
$this->_started = false;
|
||||
|
||||
if (!$this->_aggregates['fails'] && !$this->_aggregates['exceptions'])
|
||||
{
|
||||
echo ' >> ' . $this->_testCase . ' ';
|
||||
echo "\033[32mOK\033[0m" . PHP_EOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
echo ' !! ' . $this->_testCase . ' ';
|
||||
echo "\033[31mFAILED\033[0m" . PHP_EOL;
|
||||
}
|
||||
|
||||
$this->_parent->notifyEnded($this->_testCase);
|
||||
}
|
||||
|
||||
}
|
174
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/HtmlReporter.php
vendored
Normal file
174
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/HtmlReporter.php
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/Reporter.php';
|
||||
require_once 'Sweety/Reporter/HtmlTestCaseReporter.php';
|
||||
|
||||
/**
|
||||
* The reporter used for the Html (non JS) backend.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Sweety_Reporter_HtmlReporter implements Sweety_Reporter
|
||||
{
|
||||
|
||||
/**
|
||||
* Template data.
|
||||
* @var mixed[]
|
||||
*/
|
||||
public $_tplVars;
|
||||
|
||||
/**
|
||||
* True if this repoter is running.
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
private $_started = false;
|
||||
|
||||
/**
|
||||
* Set template vars.
|
||||
* @param mixed[]
|
||||
*/
|
||||
public function setTemplateVars(&$vars)
|
||||
{
|
||||
$this->_tplVars =& $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used so test case reporters can notify this reporter when they've completed.
|
||||
* @param string $testCase
|
||||
*/
|
||||
public function notifyEnded($testCase)
|
||||
{
|
||||
$this->_tplVars['runTests'][] = $testCase;
|
||||
$this->_tplVars['runCount']++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reporter used to report on this specific test case.
|
||||
* @param string $testCase
|
||||
* @return Sweety_Reporter
|
||||
*/
|
||||
public function getReporterFor($testCase)
|
||||
{
|
||||
$this->_tplVars['caseCount']++;
|
||||
|
||||
$reporter = new Sweety_Reporter_HtmlTestCaseReporter($testCase, $this);
|
||||
$reporter->setTemplateVars($this->_tplVars);
|
||||
return $reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if start() has been invoked.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStarted()
|
||||
{
|
||||
return $this->_started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start reporting.
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
$this->_started = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a skipped test case.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportSkip($message, $path)
|
||||
{
|
||||
$this->_tplVars['messages'][] = array(
|
||||
'type' => 'skip',
|
||||
'path' => $path,
|
||||
'text' => $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a passing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportPass($message, $path)
|
||||
{
|
||||
$this->_tplVars['passCount']++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a failing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportFail($message, $path)
|
||||
{
|
||||
$this->_tplVars['failCount']++;
|
||||
$this->_tplVars['messages'][] = array(
|
||||
'type' => 'fail',
|
||||
'path' => $path,
|
||||
'text' => $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an unexpected exception.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportException($message, $path)
|
||||
{
|
||||
$this->_tplVars['exceptionCount']++;
|
||||
$this->_tplVars['messages'][] = array(
|
||||
'type' => 'exception',
|
||||
'path' => $path,
|
||||
'text' => $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report output from something like a dump().
|
||||
* @param string $output
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportOutput($output, $path)
|
||||
{
|
||||
$this->_tplVars['messages'][] = array(
|
||||
'type' => 'output',
|
||||
'path' => $path,
|
||||
'text' => $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* End reporting.
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
$this->_started = false;
|
||||
|
||||
if (!$this->_tplVars['failCount'] && !$this->_tplVars['exceptionCount']
|
||||
&& $this->_tplVars['caseCount'] == $this->_tplVars['runCount'])
|
||||
{
|
||||
$this->_tplVars['result'] = 'pass';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_tplVars['result'] = 'fail';
|
||||
}
|
||||
|
||||
$incomplete = $this->_tplVars['caseCount'] - $this->_tplVars['runCount'];
|
||||
|
||||
if (0 < $incomplete)
|
||||
{
|
||||
$this->_tplVars['messages'][] = array(
|
||||
'type' => 'internal',
|
||||
'path' => '',
|
||||
'text' => $incomplete . ' test case(s) did not complete.' .
|
||||
' This may be because invalid XML was output during the test run' .
|
||||
' and/or because an error occured.' .
|
||||
' Incomplete test cases are shown in yellow. Click the HTML link ' .
|
||||
'next to the test for more detail.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
174
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/HtmlTestCaseReporter.php
vendored
Normal file
174
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Reporter/HtmlTestCaseReporter.php
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/Reporter.php';
|
||||
require_once 'Sweety/Reporter/HtmlReporter.php';
|
||||
|
||||
/**
|
||||
* A command line reporter for an individual test case.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Sweety_Reporter_HtmlTestCaseReporter implements Sweety_Reporter
|
||||
{
|
||||
|
||||
/**
|
||||
* Template variables.
|
||||
* @var mixed[]
|
||||
*/
|
||||
public $_tplVars;
|
||||
|
||||
/**
|
||||
* True if this reporter is running.
|
||||
* @var boolean
|
||||
* @access private
|
||||
*/
|
||||
private $_started = false;
|
||||
|
||||
/**
|
||||
* The name of the test case being reported on.
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $_testCase;
|
||||
|
||||
/**
|
||||
* The parent reporter this was spawned from.
|
||||
* @var Sweety_Reporter_HtmlReporter
|
||||
* @access private
|
||||
*/
|
||||
private $_parent;
|
||||
|
||||
/**
|
||||
* Aggregate totals for this test case.
|
||||
* @var int[]
|
||||
* @access private
|
||||
*/
|
||||
private $_aggregates = array();
|
||||
|
||||
/**
|
||||
* Creates a new CliTestCaseReporter.
|
||||
* @param string $testCase
|
||||
* @param Sweety_Reporter_CliReporter The parent reporter this was spawned from.
|
||||
*/
|
||||
public function __construct($testCase, Sweety_Reporter_HtmlReporter $parent)
|
||||
{
|
||||
$this->_parent = $parent;
|
||||
$this->_testCase = $testCase;
|
||||
$this->_aggregates = array(
|
||||
'passes' => 0,
|
||||
'fails' => 0,
|
||||
'exceptions' => 0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set template data.
|
||||
* @param mixed[]
|
||||
*/
|
||||
public function setTemplateVars(&$vars)
|
||||
{
|
||||
$this->_tplVars =& $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reporter used to report on this specific test case.
|
||||
* This method is stubbed only to return itself.
|
||||
* @param string $testCase
|
||||
* @return Sweety_Reporter
|
||||
*/
|
||||
public function getReporterFor($testCase)
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if start() has been invoked.
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStarted()
|
||||
{
|
||||
return $this->_started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start reporting.
|
||||
*/
|
||||
public function start()
|
||||
{
|
||||
$this->_started = true;
|
||||
$this->_tplVars['runTests'][$this->_testCase] = 'running';
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a skipped test case.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportSkip($message, $path)
|
||||
{
|
||||
$this->_parent->reportSkip($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a passing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportPass($message, $path)
|
||||
{
|
||||
$this->_aggregates['passes']++;
|
||||
$this->_parent->reportPass($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report a failing assertion.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportFail($message, $path)
|
||||
{
|
||||
$this->_aggregates['fails']++;
|
||||
$this->_parent->reportFail($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report an unexpected exception.
|
||||
* @param string $message
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportException($message, $path)
|
||||
{
|
||||
$this->_aggregates['exceptions']++;
|
||||
$this->_parent->reportException($message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Report output from something like a dump().
|
||||
* @param string $output
|
||||
* @param string $path
|
||||
*/
|
||||
public function reportOutput($output, $path)
|
||||
{
|
||||
$this->_parent->reportOutput($output, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* End reporting.
|
||||
*/
|
||||
public function finish()
|
||||
{
|
||||
$this->_started = false;
|
||||
|
||||
if (!$this->_aggregates['fails'] && !$this->_aggregates['exceptions'])
|
||||
{
|
||||
$this->_tplVars['runTests'][$this->_testCase] = 'pass';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_tplVars['runTests'][$this->_testCase] = 'fail';
|
||||
}
|
||||
|
||||
$this->_parent->notifyEnded($this->_testCase);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/TestLocator.php';
|
||||
require_once 'Sweety/Reporter.php';
|
||||
|
||||
/**
|
||||
* Provides the interface for a remote test runner.
|
||||
* @author Chris Corbyn
|
||||
* @package Sweety
|
||||
*/
|
||||
interface Sweety_Runner
|
||||
{
|
||||
|
||||
/** Format for reporting in text mode */
|
||||
const REPORT_TEXT = 'text';
|
||||
|
||||
/** Format for reporting in XML mode */
|
||||
const REPORT_XML = 'xml';
|
||||
|
||||
/** Format for reporting in HTML mode */
|
||||
const REPORT_HTML = 'html';
|
||||
|
||||
/**
|
||||
* Provide a regular expression to filter away some classes.
|
||||
* @param string $ignoredClassRegex
|
||||
*/
|
||||
public function setIgnoredClassRegex($ignoredClassRegex);
|
||||
|
||||
/**
|
||||
* Set the reporter used for showing results/progress.
|
||||
* @param Sweety_Reporter $reporter
|
||||
*/
|
||||
public function setReporter(Sweety_Reporter $reporter);
|
||||
|
||||
/**
|
||||
* Register a new test locator instance.
|
||||
* @param Sweety_TestLocator $locator
|
||||
*/
|
||||
public function registerTestLocator(Sweety_TestLocator $locator);
|
||||
|
||||
/**
|
||||
* Run all tests in the provided directories.
|
||||
* @param string[] $directories
|
||||
* @return int
|
||||
*/
|
||||
public function runAllTests($dirs = array());
|
||||
|
||||
/**
|
||||
* Run a single test case in isolation using the provided report format.
|
||||
* @param string $testCase name
|
||||
* @param string Report format
|
||||
* @return int
|
||||
*/
|
||||
public function runTestCase($testName, $format = self::REPORT_TEXT);
|
||||
|
||||
}
|
365
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Runner/AbstractTestRunner.php
vendored
Normal file
365
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/Runner/AbstractTestRunner.php
vendored
Normal file
|
@ -0,0 +1,365 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/Runner.php';
|
||||
require_once 'Sweety/TestLocator.php';
|
||||
require_once 'Sweety/Reporter.php';
|
||||
|
||||
/**
|
||||
* Base functionality for the Sweety_Runner.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
abstract class Sweety_Runner_AbstractTestRunner implements Sweety_Runner
|
||||
{
|
||||
|
||||
/**
|
||||
* The reporter used for showing progress.
|
||||
* @var Sweety_Reporter
|
||||
* @access private
|
||||
*/
|
||||
private $_reporter;
|
||||
|
||||
/**
|
||||
* TestLocator strategies.
|
||||
* @var Sweety_TestLocator[]
|
||||
* @access private
|
||||
*/
|
||||
private $_testLocators = array();
|
||||
|
||||
/**
|
||||
* Regular expression for classes which should be ignored.
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $_ignoredClassRegex = '/^$/D';
|
||||
|
||||
/**
|
||||
* Set the reporter used for showing results.
|
||||
* @param Sweety_Reporter $reporter
|
||||
*/
|
||||
public function setReporter(Sweety_Reporter $reporter)
|
||||
{
|
||||
$this->_reporter = $reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reporter used for showing results.
|
||||
* @return Sweety_Reporter
|
||||
*/
|
||||
public function getReporter()
|
||||
{
|
||||
return $this->_reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a test locator instance.
|
||||
* @param Sweety_TestLocator $locator
|
||||
*/
|
||||
public function registerTestLocator(Sweety_TestLocator $locator)
|
||||
{
|
||||
$this->_testLocators[] = $locator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the regular expression used to filter out certain class names.
|
||||
* @param string $ignoredClassRegex
|
||||
*/
|
||||
public function setIgnoredClassRegex($ignoredClassRegex)
|
||||
{
|
||||
$this->_ignoredClassRegex = $ignoredClassRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filtering regular expression for ignoring certain classes.
|
||||
* @return string
|
||||
*/
|
||||
public function getIgnoredClassRegex()
|
||||
{
|
||||
return $this->_ignoredClassRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a single test case with the given name, using the provided output format.
|
||||
* @param string $testName
|
||||
* @param string $format (xml, text or html)
|
||||
* @return int
|
||||
*/
|
||||
public function runTestCase($testName, $format = Sweety_Runner::REPORT_TEXT)
|
||||
{
|
||||
foreach ($this->_testLocators as $locator)
|
||||
{
|
||||
if ($locator->includeTest($testName))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$testClass = new ReflectionClass($testName);
|
||||
if ($testClass->getConstructor())
|
||||
{
|
||||
//We don't want test output to be cached
|
||||
if (!SimpleReporter::inCli())
|
||||
{
|
||||
header("Cache-Control: no-cache, must-revalidate");
|
||||
header("Pragma: no-cache");
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
}
|
||||
|
||||
switch ($format)
|
||||
{
|
||||
case Sweety_Runner::REPORT_HTML:
|
||||
$reporter = new HtmlReporter();
|
||||
break;
|
||||
case Sweety_Runner::REPORT_XML:
|
||||
if (!SimpleReporter::inCli())
|
||||
{
|
||||
header("Content-Type: text/xml"); //Sigh! SimpleTest (skip() issues).
|
||||
}
|
||||
$reporter = new XmlReporter();
|
||||
break;
|
||||
case Sweety_Runner::REPORT_TEXT:
|
||||
default:
|
||||
$reporter = new TextReporter();
|
||||
break;
|
||||
}
|
||||
$test = $testClass->newInstance();
|
||||
return $test->run($reporter) ? 0 : 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use strategies to find tests which are runnable.
|
||||
* @param string[] $dirs
|
||||
* @return string[]
|
||||
*/
|
||||
protected function findTests($dirs = array())
|
||||
{
|
||||
$tests = array();
|
||||
foreach ($this->_testLocators as $locator)
|
||||
{
|
||||
$tests += $locator->getTests($dirs);
|
||||
}
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an XML response from a test case an report to the reporter.
|
||||
* @param string $xml
|
||||
* @param string $testCase
|
||||
*/
|
||||
protected function parseXml($xml, $testCase)
|
||||
{
|
||||
$reporter = $this->_reporter->getReporterFor($testCase);
|
||||
if (!$reporter->isStarted())
|
||||
{
|
||||
$reporter->start();
|
||||
}
|
||||
|
||||
$xml = str_replace("\0", '?', trim($xml));
|
||||
$xml = preg_replace('/[^\x01-\x7F]/e', 'sprintf("&#%d;", ord("$0"));', $xml); //Do something better?
|
||||
if (!empty($xml))
|
||||
{
|
||||
$document = @simplexml_load_string($xml);
|
||||
if ($document)
|
||||
{
|
||||
$this->_parseDocument($document, $testCase, $reporter);
|
||||
$reporter->finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$reporter->reportException(
|
||||
'Invalid XML response: ' .
|
||||
trim(strip_tags(
|
||||
preg_replace('/^\s*<\?xml.+<\/(?:name|pass|fail|exception)>/s', '', $xml)
|
||||
)),
|
||||
$testCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse formatted test output.
|
||||
* @param SimpleXMLElement The node containing the output
|
||||
* @param string $path to this test method
|
||||
* @access private
|
||||
*/
|
||||
private function _parseFormatted(SimpleXMLElement $formatted, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
$reporter->reportOutput((string)$formatted, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse test output.
|
||||
* @param SimpleXMLElement The node containing the output
|
||||
* @param string $path to this test method
|
||||
* @access private
|
||||
*/
|
||||
private function _parseMessage(SimpleXMLElement $message, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
$reporter->reportOutput((string)$message, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a test failure.
|
||||
* @param SimpleXMLElement The node containing the fail
|
||||
* @param string $path to this test method
|
||||
* @access private
|
||||
*/
|
||||
private function _parseFailure(SimpleXMLElement $failure, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
$reporter->reportFail((string)$failure, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an exception.
|
||||
* @param SimpleXMLElement The node containing the exception
|
||||
* @param string $path to this test method
|
||||
* @access private
|
||||
*/
|
||||
private function _parseException(SimpleXMLElement $exception, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
$reporter->reportException((string)$exception, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a pass.
|
||||
* @param SimpleXMLElement The node containing this pass.
|
||||
* @param string $path to this test method
|
||||
* @access private
|
||||
*/
|
||||
private function _parsePass(SimpleXMLElement $pass, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
$reporter->reportPass((string)$pass, $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single test case.
|
||||
* @param SimpleXMLElement The node containing the test case
|
||||
* @param string $path to this test case
|
||||
* @access private
|
||||
*/
|
||||
private function _parseTestCase(SimpleXMLElement $testCase, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
foreach ($testCase->xpath('./test') as $testMethod)
|
||||
{
|
||||
$testMethodName = (string) $this->_firstNodeValue($testMethod->xpath('./name'));
|
||||
|
||||
foreach ($testMethod->xpath('./formatted') as $formatted)
|
||||
{
|
||||
$this->_parseFormatted(
|
||||
$formatted, $path . ' -> ' . $testMethodName, $reporter);
|
||||
}
|
||||
|
||||
foreach ($testMethod->xpath('./message') as $message)
|
||||
{
|
||||
$this->_parseMessage(
|
||||
$message, $path . ' -> ' . $testMethodName, $reporter);
|
||||
}
|
||||
|
||||
foreach ($testMethod->xpath('./fail') as $failure)
|
||||
{
|
||||
$this->_parseFailure(
|
||||
$failure, $path . ' -> ' . $testMethodName, $reporter);
|
||||
}
|
||||
|
||||
foreach ($testMethod->xpath('./exception') as $exception)
|
||||
{
|
||||
$this->_parseException(
|
||||
$exception, $path . ' -> ' . $testMethodName, $reporter);
|
||||
}
|
||||
|
||||
foreach ($testMethod->xpath('./pass') as $pass)
|
||||
{
|
||||
$this->_parsePass($pass, $path . ' -> ' . $testMethodName, $reporter);
|
||||
}
|
||||
|
||||
$stdout = trim((string) $testMethod);
|
||||
if ($stdout)
|
||||
{
|
||||
$reporter->reportOutput($stdout, $path . ' -> ' . $testMethodName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the results of all tests.
|
||||
* @param SimpleXMLElement The node containing the tests
|
||||
* @param string $path to the tests
|
||||
* @access private
|
||||
*/
|
||||
private function _parseResults(SimpleXMLElement $document, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
$groups = $document->xpath('./group');
|
||||
if (!empty($groups))
|
||||
{
|
||||
foreach ($groups as $group)
|
||||
{
|
||||
$groupName = (string) $this->_firstNodeValue($group->xpath('./name'));
|
||||
$this->_parseResults($group, $path . ' -> ' . $groupName, $reporter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($document->xpath('./case') as $testCase)
|
||||
{
|
||||
$this->_parseTestCase($testCase, $path, $reporter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the entire SimpleTest XML document from a test case.
|
||||
* @param SimpleXMLElement $document to parse
|
||||
* @param string $path to the test
|
||||
* @access private
|
||||
*/
|
||||
private function _parseDocument(SimpleXMLElement $document, $path = '',
|
||||
Sweety_Reporter $reporter)
|
||||
{
|
||||
if ($everything = $this->_firstNodeValue($document->xpath('/run')))
|
||||
{
|
||||
$this->_parseResults($everything, $path, $reporter);
|
||||
}
|
||||
elseif ($skip = $this->_firstNodeValue($document->xpath('/skip')))
|
||||
{
|
||||
$reporter->reportSkip((string) $skip, $path);
|
||||
}
|
||||
}
|
||||
|
||||
protected function _sort($a, $b)
|
||||
{
|
||||
$apkg = preg_replace('/_[^_]+$/D', '', $a);
|
||||
$bpkg = preg_replace('/_[^_]+$/D', '', $b);
|
||||
if ($apkg == $bpkg)
|
||||
{
|
||||
if ($a == $b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($a > $b) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($apkg > $bpkg) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
private function _firstNodeValue($nodeSet)
|
||||
{
|
||||
$first = array_shift($nodeSet);
|
||||
return $first;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/Runner/AbstractTestRunner.php';
|
||||
|
||||
/**
|
||||
* Runs SimpleTest cases as a group via the command line.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Sweety_Runner_CliRunner extends Sweety_Runner_AbstractTestRunner
|
||||
{
|
||||
|
||||
/**
|
||||
* Directories to scan for test cases.
|
||||
* @var string[]
|
||||
* @access private
|
||||
*/
|
||||
private $_dirs = array();
|
||||
|
||||
/**
|
||||
* The command to invoke when running test cases.
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
private $_command;
|
||||
|
||||
/**
|
||||
* Creates a new CliRunner scanning the given directories, using the given
|
||||
* command and having the given name.
|
||||
* @param string[] $dirs
|
||||
* @param string $command
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct(array $dirs, $command)
|
||||
{
|
||||
$this->_dirs = $dirs;
|
||||
$this->_command = $command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all test cases found under the given directories.
|
||||
* @param string[] $directories to scan for test cases
|
||||
* @param string To be prepended to class names
|
||||
* @return int
|
||||
*/
|
||||
public function runAllTests($dirs = array())
|
||||
{
|
||||
if (empty($dirs))
|
||||
{
|
||||
$dirs = $this->_dirs;
|
||||
}
|
||||
|
||||
$reporter = $this->getReporter();
|
||||
|
||||
if (!$reporter->isStarted())
|
||||
{
|
||||
$reporter->start();
|
||||
}
|
||||
|
||||
$tests = $this->findTests($dirs);
|
||||
usort($tests, array($this, '_sort'));
|
||||
|
||||
global $argv;
|
||||
|
||||
if (!empty($argv[1]))
|
||||
{
|
||||
if (substr($argv[1], 0, 1) == '!')
|
||||
{
|
||||
$argv[1] = substr($argv[1], 1);
|
||||
foreach ($tests as $index => $name)
|
||||
{
|
||||
if (@preg_match($argv[1] . 'i', $name))
|
||||
{
|
||||
unset($tests[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($tests as $index => $name)
|
||||
{
|
||||
if (!@preg_match($argv[1] . 'i', $name))
|
||||
{
|
||||
unset($tests[$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$ret = $this->_runTestList($tests);
|
||||
|
||||
$reporter->finish();
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run all possible tests from the given list.
|
||||
* @param string[] $tests
|
||||
* @return int
|
||||
*/
|
||||
protected function _runTestList(array $tests)
|
||||
{
|
||||
foreach ($tests as $testCase)
|
||||
{
|
||||
if (preg_match($this->getIgnoredClassRegex(), $testCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$command = $this->_command;
|
||||
$command .= ' ' . $testCase;
|
||||
$command .= ' ' . Sweety_Runner::REPORT_XML;
|
||||
|
||||
exec($command, $output, $status);
|
||||
|
||||
$xml = implode(PHP_EOL, $output);
|
||||
|
||||
$this->parseXml($xml, $testCase);
|
||||
|
||||
unset($status);
|
||||
unset($output);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/Runner/AbstractTestRunner.php';
|
||||
|
||||
/**
|
||||
* Runs SimpleTest cases as a group through a JS enabled browser.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Sweety_Runner_HtmlRunner extends Sweety_Runner_AbstractTestRunner
|
||||
{
|
||||
|
||||
/**
|
||||
* The path to a valid template file.
|
||||
* @var string
|
||||
*/
|
||||
private $_template;
|
||||
|
||||
/**
|
||||
* The name of the test suite.
|
||||
* @var string
|
||||
*/
|
||||
private $_name;
|
||||
|
||||
/**
|
||||
* Creates a new HtmlRunner scanning the given directories.
|
||||
* @param string[] $dirs
|
||||
* @param string $template to load
|
||||
* @param string $name of the test suite
|
||||
*/
|
||||
public function __construct(array $dirs, $template, $name)
|
||||
{
|
||||
$this->_dirs = $dirs;
|
||||
$this->_template = $template;
|
||||
$this->_name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all test cases found under the given directories.
|
||||
* @param string[] $directories to scan for test cases
|
||||
* @param string To be prepended to class names
|
||||
* @return int
|
||||
*/
|
||||
public function runAllTests($dirs = array())
|
||||
{
|
||||
//We don't want test output to be cached
|
||||
header("Cache-Control: no-cache, must-revalidate");
|
||||
header("Pragma: no-cache");
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
|
||||
if (empty($dirs))
|
||||
{
|
||||
$dirs = $this->_dirs;
|
||||
}
|
||||
|
||||
$testCases = $this->findTests($dirs);
|
||||
foreach ($testCases as $k => $testCase)
|
||||
{
|
||||
if (preg_match($this->getIgnoredClassRegex(), $testCase))
|
||||
{
|
||||
unset($testCases[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
usort($testCases, array($this, '_sort'));
|
||||
|
||||
$vars = array(
|
||||
//String
|
||||
'testCases' => $testCases,
|
||||
//String
|
||||
'suiteName' => $this->_name,
|
||||
// testCase => pass | fail | running
|
||||
'runTests' => array(),
|
||||
//Integer
|
||||
'caseCount' => 0,
|
||||
//Integer
|
||||
'runCount' => 0,
|
||||
//Integer
|
||||
'passCount' => 0,
|
||||
//Integer
|
||||
'failCount' => 0,
|
||||
//Integer
|
||||
'exceptionCount' => 0,
|
||||
// type => pass | fail | exception | output | internal, path => testCase, text => ...
|
||||
'messages' => array(),
|
||||
// pass | fail
|
||||
'result' => 'idle'
|
||||
);
|
||||
|
||||
if (isset($_REQUEST['runtests']))
|
||||
{
|
||||
$reporter = $this->getReporter();
|
||||
$reporter->setTemplateVars($vars);
|
||||
|
||||
if (!$reporter->isStarted())
|
||||
{
|
||||
$reporter->start();
|
||||
}
|
||||
|
||||
$this->_runTestList((array)$_REQUEST['runtests'], $reporter);
|
||||
|
||||
$reporter->finish();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($testCases as $testCase)
|
||||
{
|
||||
$vars['runTests'][$testCase] = 'idle'; //Show all checked by default
|
||||
}
|
||||
}
|
||||
|
||||
$this->_render($vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run tests in the given array using the REST API (kind of).
|
||||
* @param string[] $tests
|
||||
* @param Sweety_Reporter $reporter
|
||||
* @return int
|
||||
*/
|
||||
protected function _runTestList(array $tests, Sweety_Reporter $reporter)
|
||||
{
|
||||
$protocol = !empty($_SERVER['HTTPS']) ? 'https://' : 'http://';
|
||||
|
||||
//Most likely a HTTP/1.0 server not supporting HOST header
|
||||
$server = !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '127.0.0.1';
|
||||
|
||||
$path = '/';
|
||||
if (!empty($_SERVER['REQUEST_URI']))
|
||||
{
|
||||
$path = preg_replace('/\?.*$/sD', '', $_SERVER['REQUEST_URI']);
|
||||
}
|
||||
|
||||
$baseUrl = $protocol . $server . $path;
|
||||
|
||||
foreach ($tests as $testCase)
|
||||
{
|
||||
$url = $baseUrl . '?test=' . $testCase . '&format=xml';
|
||||
$xml = file_get_contents($url);
|
||||
$this->parseXml($xml, $testCase);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the view for the suite.
|
||||
* @param string[] $templateVars
|
||||
*/
|
||||
protected function _render($vars = array())
|
||||
{
|
||||
foreach ($vars as $k => $v)
|
||||
{
|
||||
$$k = $v;
|
||||
}
|
||||
|
||||
require_once $this->_template;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Interface for any strategy for finding test cases.
|
||||
* @package Sweety
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
interface Sweety_TestLocator
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns an array of all test cases found under the given directories.
|
||||
* @param string[] $dirs
|
||||
* @return string[]
|
||||
*/
|
||||
public function getTests($dirs = array());
|
||||
|
||||
/**
|
||||
* Loads the test case of the given name.
|
||||
* @param string $testCase
|
||||
* @return boolean
|
||||
*/
|
||||
public function includeTest($testCase);
|
||||
|
||||
}
|
71
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/TestLocator/PearStyleLocator.php
vendored
Normal file
71
vendor/swiftmailer/swiftmailer/test-suite/lib/Sweety/TestLocator/PearStyleLocator.php
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
require_once 'Sweety/TestLocator.php';
|
||||
|
||||
class Sweety_TestLocator_PearStyleLocator implements Sweety_TestLocator
|
||||
{
|
||||
|
||||
private $_testCache = array();
|
||||
|
||||
public function getTests($dirs = array())
|
||||
{
|
||||
return $this->_findTestCases($dirs);
|
||||
}
|
||||
|
||||
public function includeTest($testCase)
|
||||
{
|
||||
$file = str_replace('_', '/', $testCase) . '.php';
|
||||
foreach (explode(PATH_SEPARATOR, get_include_path()) as $dir)
|
||||
{
|
||||
if (is_file($dir . '/' . $file))
|
||||
{
|
||||
require_once $dir . '/' . $file;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function _findTestCases($dirs = array(), $prepend = '')
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
foreach ($dirs as $dir)
|
||||
{
|
||||
if (array_key_exists($dir, $this->_testCache))
|
||||
{
|
||||
$ret += $this->_testCache[$dir];
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->_testCache[$dir] = array();
|
||||
|
||||
$handle = opendir($dir);
|
||||
while (false !== $file = readdir($handle))
|
||||
{
|
||||
if (substr($file, 0, 1) != '.' && is_dir($dir . '/' . $file))
|
||||
{
|
||||
foreach ($this->_findTestCases(
|
||||
array($dir . '/' . $file), $prepend . $file . '_') as $add)
|
||||
{
|
||||
$this->_testCache[$dir][] = $add;
|
||||
$ret[] = $add;
|
||||
}
|
||||
}
|
||||
elseif (substr($file, -4) == '.php')
|
||||
{
|
||||
$className = $prepend . basename($file, '.php');
|
||||
$this->_testCache[$dir][] = $className;
|
||||
$ret[] = $className;
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
sort($ret);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
}
|
383
vendor/swiftmailer/swiftmailer/test-suite/lib/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE
vendored
Normal file
383
vendor/swiftmailer/swiftmailer/test-suite/lib/simpletest/HELP_MY_TESTS_DONT_WORK_ANYMORE
vendored
Normal file
|
@ -0,0 +1,383 @@
|
|||
Simple Test interface changes
|
||||
=============================
|
||||
Because the SimpleTest tool set is still evolving it is likely that tests
|
||||
written with earlier versions will fail with the newest ones. The most
|
||||
dramatic changes are in the alpha releases. Here is a list of possible
|
||||
problems and their fixes...
|
||||
|
||||
Fatal error: Call to undefined method Classname::classname()
|
||||
------------------------------------------------------------
|
||||
SimpleTest renamed all of its constructors from
|
||||
Classname to __construct; derived classes invoking
|
||||
their parent constructors should replace parent::Classname()
|
||||
with parent::__construct().
|
||||
|
||||
Custom CSS in HtmlReporter not being applied
|
||||
--------------------------------------------
|
||||
Batch rename of protected and private methods
|
||||
means that _getCss() was renamed to getCss();
|
||||
replace your function definition accordingly.
|
||||
|
||||
setReturnReference() throws errors in E_STRICT
|
||||
----------------------------------------------
|
||||
Happens when an object is passed by reference.
|
||||
This also happens with setReturnReferenceAt().
|
||||
If you want to return objects then replace these
|
||||
with calls to returns() and returnsAt() with the
|
||||
same arguments. This change was forced in the 1.1
|
||||
version for E_STRICT compatibility.
|
||||
|
||||
assertReference() throws errors in E_STRICT
|
||||
-------------------------------------------
|
||||
Due to language restrictions you cannot compare
|
||||
both variables and objects in E_STRICT mode. Use
|
||||
assertSame() in this mode with objects. This change
|
||||
was forced the 1.1 version.
|
||||
|
||||
Cannot create GroupTest
|
||||
-----------------------
|
||||
The GroupTest has been renamed TestSuite (see below).
|
||||
It was removed completely in 1.1 in favour of this
|
||||
name.
|
||||
|
||||
No method getRelativeUrls() or getAbsoluteUrls()
|
||||
------------------------------------------------
|
||||
These methods were always a bit weird anyway, and
|
||||
the new parsing of the base tag makes them more so.
|
||||
They have been replaced with getUrls() instead. If
|
||||
you want the old functionality then simply chop
|
||||
off the current domain from getUrl().
|
||||
|
||||
Method setWildcard() removed in mocks
|
||||
-------------------------------------
|
||||
Even setWildcard() has been removed in 1.0.1beta now.
|
||||
If you want to test explicitely for a '*' string, then
|
||||
simply pass in new IdenticalExpectation('*') instead.
|
||||
|
||||
No method _getTest() on mocks
|
||||
-----------------------------
|
||||
This has finally been removed. It was a pretty esoteric
|
||||
flex point anyway. It was there to allow the mocks to
|
||||
work with other test tools, but no one does this.
|
||||
|
||||
No method assertError(), assertNoErrors(), swallowErrors()
|
||||
----------------------------------------------------------
|
||||
These have been deprecated in 1.0.1beta in favour of
|
||||
expectError() and expectException(). assertNoErrors() is
|
||||
redundant if you use expectError() as failures are now reported
|
||||
immediately.
|
||||
|
||||
No method TestCase::signal()
|
||||
----------------------------
|
||||
This has been deprecated in favour of triggering an error or
|
||||
throwing an exception. Deprecated as of 1.0.1beta.
|
||||
|
||||
No method TestCase::sendMessage()
|
||||
---------------------------------
|
||||
This has been deprecated as of 1.0.1beta.
|
||||
|
||||
Failure to connect now emits failures
|
||||
-------------------------------------
|
||||
It used to be that you would have to use the
|
||||
getTransferError() call on the web tester to see if
|
||||
there was a socket level error in a fetch. This check
|
||||
is now always carried out by the WebTestCase unless
|
||||
the fetch is prefaced with WebTestCase::ignoreErrors().
|
||||
The ignore directive only lasts for test case fetching
|
||||
action such as get() and click().
|
||||
|
||||
No method SimpleTestOptions::ignore()
|
||||
-------------------------------------
|
||||
This is deprecated in version 1.0.1beta and has been moved
|
||||
to SimpleTest::ignore() as that is more readable. In
|
||||
addition, parent classes are also ignored automatically.
|
||||
If you are using PHP5 you can skip this directive simply
|
||||
by marking your test case as abstract.
|
||||
|
||||
No method assertCopy()
|
||||
----------------------
|
||||
This is deprecated in 1.0.1 in favour of assertClone().
|
||||
The assertClone() method is slightly different in that
|
||||
the objects must be identical, but without being a
|
||||
reference. It is thus not a strict inversion of
|
||||
assertReference().
|
||||
|
||||
Constructor wildcard override has no effect in mocks
|
||||
----------------------------------------------------
|
||||
As of 1.0.1beta this is now set with setWildcard() instead
|
||||
of in the constructor.
|
||||
|
||||
No methods setStubBaseClass()/getStubBaseClass()
|
||||
------------------------------------------------
|
||||
As mocks are now used instead of stubs, these methods
|
||||
stopped working and are now removed as of the 1.0.1beta
|
||||
release. The mock objects may be freely used instead.
|
||||
|
||||
No method addPartialMockCode()
|
||||
------------------------------
|
||||
The ability to insert arbitrary partial mock code
|
||||
has been removed. This was a low value feature
|
||||
causing needless complications. It was removed
|
||||
in the 1.0.1beta release.
|
||||
|
||||
No method setMockBaseClass()
|
||||
----------------------------
|
||||
The ability to change the mock base class has been
|
||||
scheduled for removal and is deprecated since the
|
||||
1.0.1beta version. This was a rarely used feature
|
||||
except as a workaround for PHP5 limitations. As
|
||||
these limitations are being resolved it's hoped
|
||||
that the bundled mocks can be used directly.
|
||||
|
||||
No class Stub
|
||||
-------------
|
||||
Server stubs are deprecated from 1.0.1 as the mocks now
|
||||
have exactly the same interface. Just use mock objects
|
||||
instead.
|
||||
|
||||
No class SimpleTestOptions
|
||||
--------------------------
|
||||
This was replced by the shorter SimpleTest in 1.0.1beta1
|
||||
and is since deprecated.
|
||||
|
||||
No file simple_test.php
|
||||
-----------------------
|
||||
This was renamed test_case.php in 1.0.1beta to more accurately
|
||||
reflect it's purpose. This file should never be directly
|
||||
included in test suites though, as it's part of the
|
||||
underlying mechanics and has a tendency to be refactored.
|
||||
|
||||
No class WantedPatternExpectation
|
||||
---------------------------------
|
||||
This was deprecated in 1.0.1alpha in favour of the simpler
|
||||
name PatternExpectation.
|
||||
|
||||
No class NoUnwantedPatternExpectation
|
||||
-------------------------------------
|
||||
This was deprecated in 1.0.1alpha in favour of the simpler
|
||||
name NoPatternExpectation.
|
||||
|
||||
No method assertNoUnwantedPattern()
|
||||
-----------------------------------
|
||||
This has been renamed to assertNoPattern() in 1.0.1alpha and
|
||||
the old form is deprecated.
|
||||
|
||||
No method assertWantedPattern()
|
||||
-------------------------------
|
||||
This has been renamed to assertPattern() in 1.0.1alpha and
|
||||
the old form is deprecated.
|
||||
|
||||
No method assertExpectation()
|
||||
-----------------------------
|
||||
This was renamed as assert() in 1.0.1alpha and the old form
|
||||
has been deprecated.
|
||||
|
||||
No class WildcardExpectation
|
||||
----------------------------
|
||||
This was a mostly internal class for the mock objects. It was
|
||||
renamed AnythingExpectation to bring it closer to JMock and
|
||||
NMock in version 1.0.1alpha.
|
||||
|
||||
Missing UnitTestCase::assertErrorPattern()
|
||||
------------------------------------------
|
||||
This method is deprecated for version 1.0.1 onwards.
|
||||
This method has been subsumed by assertError() that can now
|
||||
take an expectation. Simply pass a PatternExpectation
|
||||
into assertError() to simulate the old behaviour.
|
||||
|
||||
No HTML when matching page elements
|
||||
-----------------------------------
|
||||
This behaviour has been switched to using plain text as if it
|
||||
were seen by the user of the browser. This means that HTML tags
|
||||
are suppressed, entities are converted and whitespace is
|
||||
normalised. This should make it easier to match items in forms.
|
||||
Also images are replaced with their "alt" text so that they
|
||||
can be matched as well.
|
||||
|
||||
No method SimpleRunner::_getTestCase()
|
||||
--------------------------------------
|
||||
This was made public as getTestCase() in 1.0RC2.
|
||||
|
||||
No method restartSession()
|
||||
--------------------------
|
||||
This was renamed to restart() in the WebTestCase, SimpleBrowser
|
||||
and the underlying SimpleUserAgent in 1.0RC2. Because it was
|
||||
undocumented anyway, no attempt was made at backward
|
||||
compatibility.
|
||||
|
||||
My custom test case ignored by tally()
|
||||
--------------------------------------
|
||||
The _assertTrue method has had it's signature changed due to a bug
|
||||
in the PHP 5.0.1 release. You must now use getTest() from within
|
||||
that method to get the test case. Mock compatibility with other
|
||||
unit testers is now deprecated as of 1.0.1alpha as PEAR::PHPUnit2
|
||||
should soon have mock support of it's own.
|
||||
|
||||
Broken code extending SimpleRunner
|
||||
----------------------------------
|
||||
This was replaced with SimpleScorer so that I could use the runner
|
||||
name in another class. This happened in RC1 development and there
|
||||
is no easy backward compatibility fix. The solution is simply to
|
||||
extend SimpleScorer instead.
|
||||
|
||||
Missing method getBaseCookieValue()
|
||||
-----------------------------------
|
||||
This was renamed getCurrentCookieValue() in RC1.
|
||||
|
||||
Missing files from the SimpleTest suite
|
||||
---------------------------------------
|
||||
Versions of SimpleTest prior to Beta6 required a SIMPLE_TEST constant
|
||||
to point at the SimpleTest folder location before any of the toolset
|
||||
was loaded. This is no longer documented as it is now unnecessary
|
||||
for later versions. If you are using an earlier version you may
|
||||
need this constant. Consult the documentation that was bundled with
|
||||
the release that you are using or upgrade to Beta6 or later.
|
||||
|
||||
No method SimpleBrowser::getCurrentUrl()
|
||||
--------------------------------------
|
||||
This is replaced with the more versatile showRequest() for
|
||||
debugging. It only existed in this context for version Beta5.
|
||||
Later versions will have SimpleBrowser::getHistory() for tracking
|
||||
paths through pages. It is renamed as getUrl() since 1.0RC1.
|
||||
|
||||
No method Stub::setStubBaseClass()
|
||||
----------------------------------
|
||||
This method has finally been removed in 1.0RC1. Use
|
||||
SimpleTestOptions::setStubBaseClass() instead.
|
||||
|
||||
No class CommandLineReporter
|
||||
----------------------------
|
||||
This was renamed to TextReporter in Beta3 and the deprecated version
|
||||
was removed in 1.0RC1.
|
||||
|
||||
No method requireReturn()
|
||||
-------------------------
|
||||
This was deprecated in Beta3 and is now removed.
|
||||
|
||||
No method expectCookie()
|
||||
------------------------
|
||||
This method was abruptly removed in Beta4 so as to simplify the internals
|
||||
until another mechanism can replace it. As a workaround it is necessary
|
||||
to assert that the cookie has changed by setting it before the page
|
||||
fetch and then assert the desired value.
|
||||
|
||||
No method clickSubmitByFormId()
|
||||
-------------------------------
|
||||
This method had an incorrect name as no button was involved. It was
|
||||
renamed to submitByFormId() in Beta4 and the old version deprecated.
|
||||
Now removed.
|
||||
|
||||
No method paintStart() or paintEnd()
|
||||
------------------------------------
|
||||
You should only get this error if you have subclassed the lower level
|
||||
reporting and test runner machinery. These methods have been broken
|
||||
down into events for test methods, events for test cases and events
|
||||
for group tests. The new methods are...
|
||||
|
||||
paintStart() --> paintMethodStart(), paintCaseStart(), paintGroupStart()
|
||||
paintEnd() --> paintMethodEnd(), paintCaseEnd(), paintGroupEnd()
|
||||
|
||||
This change was made in Beta3, ironically to make it easier to subclass
|
||||
the inner machinery. Simply duplicating the code you had in the previous
|
||||
methods should provide a temporary fix.
|
||||
|
||||
No class TestDisplay
|
||||
--------------------
|
||||
This has been folded into SimpleReporter in Beta3 and is now deprecated.
|
||||
It was removed in RC1.
|
||||
|
||||
No method WebTestCase::fetch()
|
||||
------------------------------
|
||||
This was renamed get() in Alpha8. It is removed in Beta3.
|
||||
|
||||
No method submit()
|
||||
------------------
|
||||
This has been renamed clickSubmit() in Beta1. The old method was
|
||||
removed in Beta2.
|
||||
|
||||
No method clearHistory()
|
||||
------------------------
|
||||
This method is deprecated in Beta2 and removed in RC1.
|
||||
|
||||
No method getCallCount()
|
||||
------------------------
|
||||
This method has been deprecated since Beta1 and has now been
|
||||
removed. There are now more ways to set expectations on counts
|
||||
and so this method should be unecessery. Removed in RC1.
|
||||
|
||||
Cannot find file *
|
||||
------------------
|
||||
The following public name changes have occoured...
|
||||
|
||||
simple_html_test.php --> reporter.php
|
||||
simple_mock.php --> mock_objects.php
|
||||
simple_unit.php --> unit_tester.php
|
||||
simple_web.php --> web_tester.php
|
||||
|
||||
The old names were deprecated in Alpha8 and removed in Beta1.
|
||||
|
||||
No method attachObserver()
|
||||
--------------------------
|
||||
Prior to the Alpha8 release the old internal observer pattern was
|
||||
gutted and replaced with a visitor. This is to trade flexibility of
|
||||
test case expansion against the ease of writing user interfaces.
|
||||
|
||||
Code such as...
|
||||
|
||||
$test = &new MyTestCase();
|
||||
$test->attachObserver(new TestHtmlDisplay());
|
||||
$test->run();
|
||||
|
||||
...should be rewritten as...
|
||||
|
||||
$test = &new MyTestCase();
|
||||
$test->run(new HtmlReporter());
|
||||
|
||||
If you previously attached multiple observers then the workaround
|
||||
is to run the tests twice, once with each, until they can be combined.
|
||||
For one observer the old method is simulated in Alpha 8, but is
|
||||
removed in Beta1.
|
||||
|
||||
No class TestHtmlDisplay
|
||||
------------------------
|
||||
This class has been renamed to HtmlReporter in Alpha8. It is supported,
|
||||
but deprecated in Beta1 and removed in Beta2. If you have subclassed
|
||||
the display for your own design, then you will have to extend this
|
||||
class (HtmlReporter) instead.
|
||||
|
||||
If you have accessed the event queue by overriding the notify() method
|
||||
then I am afraid you are in big trouble :(. The reporter is now
|
||||
carried around the test suite by the runner classes and the methods
|
||||
called directly. In the unlikely event that this is a problem and
|
||||
you don't want to upgrade the test tool then simplest is to write your
|
||||
own runner class and invoke the tests with...
|
||||
|
||||
$test->accept(new MyRunner(new MyReporter()));
|
||||
|
||||
...rather than the run method. This should be easier to extend
|
||||
anyway and gives much more control. Even this method is overhauled
|
||||
in Beta3 where the runner class can be set within the test case. Really
|
||||
the best thing to do is to upgrade to this version as whatever you were
|
||||
trying to achieve before should now be very much easier.
|
||||
|
||||
Missing set options method
|
||||
--------------------------
|
||||
All test suite options are now in one class called SimpleTestOptions.
|
||||
This means that options are set differently...
|
||||
|
||||
GroupTest::ignore() --> SimpleTestOptions::ignore()
|
||||
Mock::setMockBaseClass() --> SimpleTestOptions::setMockBaseClass()
|
||||
|
||||
These changed in Alpha8 and the old versions are now removed in RC1.
|
||||
|
||||
No method setExpected*()
|
||||
------------------------
|
||||
The mock expectations changed their names in Alpha4 and the old names
|
||||
ceased to be supported in Alpha8. The changes are...
|
||||
|
||||
setExpectedArguments() --> expectArguments()
|
||||
setExpectedArgumentsSequence() --> expectArgumentsAt()
|
||||
setExpectedCallCount() --> expectCallCount()
|
||||
setMaximumCallCount() --> expectMaximumCallCount()
|
||||
|
||||
The parameters remained the same.
|
|
@ -0,0 +1,502 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,108 @@
|
|||
SimpleTest
|
||||
==========
|
||||
You probably got this package from...
|
||||
http://simpletest.sourceforge.net/projects/simpletest/
|
||||
|
||||
If there is no licence agreement with this package please download
|
||||
a version from the location above. You must read and accept that
|
||||
licence to use this software. The file is titled simply LICENSE.
|
||||
|
||||
What is it? It's a framework for unit testing, web site testing and
|
||||
mock objects for PHP 5.0.5+.
|
||||
|
||||
If you have used JUnit, you will find this PHP unit testing version very
|
||||
similar. Also included is a mock objects and server stubs generator.
|
||||
The stubs can have return values set for different arguments, can have
|
||||
sequences set also by arguments and can return items by reference.
|
||||
The mocks inherit all of this functionality and can also have
|
||||
expectations set, again in sequences and for different arguments.
|
||||
|
||||
A web tester similar in concept to JWebUnit is also included. There is no
|
||||
JavaScript or tables support, but forms, authentication, cookies and
|
||||
frames are handled.
|
||||
|
||||
You can see a release schedule at http://simpletest.org/en/overview.html
|
||||
which is also copied to the documentation folder with this release.
|
||||
A full PHPDocumenter API documentation exists at
|
||||
http://simpletest.org/api/.
|
||||
|
||||
The user interface is minimal
|
||||
in the extreme, but a lot of information flows from the test suite.
|
||||
After version 1.0 we will release a better web UI, but we are leaving XUL
|
||||
and GTk versions to volunteers as everybody has their own opinion
|
||||
on a good GUI, and we don't want to discourage development by shipping
|
||||
one with the toolkit. You can download an Eclipse plug-in separately.
|
||||
|
||||
You are looking at a second full release. The unit tests for SimpleTest
|
||||
itself can be run here...
|
||||
|
||||
simpletest/test/unit_tests.php
|
||||
|
||||
And tests involving live network connections as well are here...
|
||||
|
||||
simpletest/test/all_tests.php
|
||||
|
||||
The full tests will typically overrun the 8Mb limit often allowed
|
||||
to a PHP process. A workaround is to run the tests on the command
|
||||
with a custom php.ini file if you do not have access to your server
|
||||
version.
|
||||
|
||||
You will have to edit the all_tests.php file if you are accesssing
|
||||
the internet through a proxy server. See the comments in all_tests.php
|
||||
for instructions.
|
||||
|
||||
The full tests read some test data from the LastCraft site. If the site
|
||||
is down or has been modified for a later version then you will get
|
||||
spurious errors. A unit_tests.php failure on the other hand would be
|
||||
very serious. As far as we know we haven't yet managed to check in any
|
||||
unit test failures, so please correct us if you find one.
|
||||
|
||||
Even if all of the tests run please verify that your existing test suites
|
||||
also function as expected. If they don't see the file...
|
||||
|
||||
HELP_MY_TESTS_DONT_WORK_ANYMORE
|
||||
|
||||
This contains information on interface changes. It also points out
|
||||
deprecated interfaces, so you should read this even if all of
|
||||
your current tests appear to run.
|
||||
|
||||
There is a documentation folder which contains the core reference information
|
||||
in English and French, although this information is fairly basic.
|
||||
You can find a tutorial on...
|
||||
|
||||
http://simpletest.org/en/first_test_tutorial.html
|
||||
|
||||
...to get you started and this material will eventually become included
|
||||
with the project documentation. A French translation exists at...
|
||||
|
||||
http://simpletest.org/fr/first_test_tutorial.html
|
||||
|
||||
If you download and use, and possibly even extend this tool, please let us
|
||||
know. Any feedback, even bad, is always welcome and we will work to get
|
||||
your suggestions into the next release. Ideally please send your
|
||||
comments to...
|
||||
|
||||
simpletest-support@lists.sourceforge.net
|
||||
|
||||
...so that others can read them too. We usually try to respond within 48
|
||||
hours.
|
||||
|
||||
There is no change log except at Sourceforge. You can visit the
|
||||
release notes to see the completed TODO list after each cycle and also the
|
||||
status of any bugs, but if the bug is recent then it will be fixed in SVN only.
|
||||
The SVN check-ins always have all the tests passing and so SVN snapshots should
|
||||
be pretty usable, although the code may not look so good internally.
|
||||
|
||||
Oh, yes. It is called "Simple" because it should be simple to
|
||||
use. We intend to add a complete set of tools for a test first
|
||||
and "test as you code" type of development. "Simple" does not
|
||||
mean "Lite" in this context.
|
||||
|
||||
Thanks to everyone who has sent comments and offered suggestions. They
|
||||
really are invaluable, but sadly you are too many to mention in full.
|
||||
Thanks to all on the advanced PHP forum on SitePoint, especially Harry
|
||||
Fuecks. Early adopters are always an inspiration.
|
||||
|
||||
Marcus Baker, Jason Sweat, Travis Swicegood, Perrick Penet and Edward Z. Yang.
|
||||
--
|
||||
marcus@lastcraft.com
|
|
@ -0,0 +1,176 @@
|
|||
<?xml version="1.0"?>
|
||||
<page title="TODO tasks for the current iteration" here="TODO">
|
||||
<long_title>TODO tasks for the current iteration</long_title>
|
||||
<content>
|
||||
<section name="release-process" title="Release process">
|
||||
<p>
|
||||
The following is the approximate plan for the next full point release.
|
||||
</p>
|
||||
<p>
|
||||
Before each release we hope to have the following done.
|
||||
More may get done, depending on the interest of the volunteers,
|
||||
but this is the current minimum.
|
||||
</p>
|
||||
<p>
|
||||
The aim of this release cycle is to produce a functionally
|
||||
identical version to the 1.0.1 release, but bug-fixed and
|
||||
fully compatible with PHP 5.0.5+ under E_STRICT.
|
||||
We are also hoping to flush out issues and use cases
|
||||
caused by people hacking against unpublished flex points
|
||||
in SimpleTest.
|
||||
We want to break people's code now, not while we are developing
|
||||
features down the line.
|
||||
</p>
|
||||
<p>
|
||||
With the website move to a new server, and more developers,
|
||||
we are able and need to improve the test automation and developer
|
||||
cooperation.
|
||||
This release is a deep drawing of breath before going forward.
|
||||
</p>
|
||||
</section>
|
||||
<section name="plan" title="Release plan" version="1.1">
|
||||
<milestone version="1.1beta">
|
||||
<concern name="unit-tester">
|
||||
<bug tracker="1896582">Undefined property $_reporter + fatal error</bug>
|
||||
</concern>
|
||||
<concern name="reporter"/>
|
||||
<concern name="mock-objects"/>
|
||||
<concern name="parser"/>
|
||||
<concern name="browser"/>
|
||||
<concern name="web-tester"/>
|
||||
<concern name="documentation">
|
||||
<task>
|
||||
The HELP_MY_TESTS_DONT_WORK_ANYMORE needs to be updated.
|
||||
</task>
|
||||
<task>README needs to be updated.</task>
|
||||
<task status="done">
|
||||
Write XSLT code for this file so Perrick doesn't strangle me
|
||||
</task>
|
||||
</concern>
|
||||
<concern name="extensions">
|
||||
<task>Ensure extensions are compatible with PHP5 constructor renaming in the current trunk.</task>
|
||||
</concern>
|
||||
<concern name="build">
|
||||
<task>Update PEAR package task to be compatible with latest PEAR installer.</task>
|
||||
<task status="done">PHP 5.3 compatible under E_STRICT</task>
|
||||
<task>PHP 5.2.0-5 compatible under E_STRICT</task>
|
||||
<task>PHP 5.1.0-6 compatible under E_STRICT</task>
|
||||
<bug tracker="1884013">continuous integration</bug>
|
||||
<bug tracker="1853765">error_reporting(E_ALL|E_STRICT)gives lots of warning</bug>
|
||||
<task>Remove all deprecated methods</task>
|
||||
<task status="done">
|
||||
Drop underscores from protected methods and
|
||||
private variables.
|
||||
Make all variables private and add protected
|
||||
accessors where we use them internally.
|
||||
<note>
|
||||
That way people will start complaining.
|
||||
Upon each complaint we'll add an accessor and
|
||||
capture the use case from them.
|
||||
</note>
|
||||
<note>We'll stick the use cases in the feature request tracker for now</note>
|
||||
</task>
|
||||
<task status="done">Move web site to new server</task>
|
||||
</concern>
|
||||
</milestone>
|
||||
<milestone version="1.1beta2">
|
||||
<concern name="unit-tester"/>
|
||||
<concern name="reporter">
|
||||
<task>
|
||||
Deprecate all mentions of GroupTest without breaking
|
||||
existing code.
|
||||
<note>
|
||||
Need to swap the terminology for TestSuite
|
||||
in method names, etc.
|
||||
</note>
|
||||
</task>
|
||||
<bug tracker="1864974">XmlReporter generating invalid XML</bug>
|
||||
</concern>
|
||||
<concern name="mock-objects">
|
||||
<task>Remove reflection facade for PHP4</task>
|
||||
</concern>
|
||||
<concern name="parser"/>
|
||||
<concern name="browser">
|
||||
<bug tracker="1913229">label not assigned to radio and checkbox</bug>
|
||||
<bug tracker="1706283">incorrect proxy requests</bug>
|
||||
</concern>
|
||||
<concern name="web-tester"/>
|
||||
<concern name="documentation">
|
||||
<task>Docblocks need to be cut back to a minimum</task>
|
||||
</concern>
|
||||
<concern name="extensions"/>
|
||||
<concern name="build">
|
||||
<task>PHP 5.0.5 compatible under E_STRICT</task>
|
||||
<task>Move acceptance tests sample pages to new server</task>
|
||||
</concern>
|
||||
</milestone>
|
||||
<milestone version="1.1RC1">
|
||||
<concern name="unit-tester"/>
|
||||
<concern name="reporter"/>
|
||||
<concern name="mock-objects">
|
||||
<task>Remove reflection facade for PHP4</task>
|
||||
</concern>
|
||||
<concern name="parser"/>
|
||||
<concern name="browser"/>
|
||||
<concern name="web-tester"/>
|
||||
<concern name="documentation">
|
||||
<task>Throw away old tutorial</task>
|
||||
</concern>
|
||||
<concern name="extensions"/>
|
||||
<concern name="build">
|
||||
<task>PHP 6 compatible under E_STRICT</task>
|
||||
<task>
|
||||
Automated nightly test script that runs tests on all
|
||||
targeted PHP versions.
|
||||
</task>
|
||||
</concern>
|
||||
</milestone>
|
||||
</section>
|
||||
</content>
|
||||
<internal>
|
||||
<link>
|
||||
<a href="#plan">Current iteration</a> is 1.1beta.
|
||||
</link>
|
||||
<link>
|
||||
Upcoming tasks for
|
||||
<a href="#unit-tester">Unit tester</a>,
|
||||
<a href="#reporter">Reporter</a>,
|
||||
<a href="#mock-objects">Mock objects</a>,
|
||||
<a href="#parser">Parser</a>,
|
||||
<a href="#browser">Browser</a>,
|
||||
<a href="#web-tester">Web tester</a>,
|
||||
<a href="#documentation">Documentation</a>,
|
||||
<a href="#extensions">Extensions</a> and
|
||||
<a href="#build">Build</a>.
|
||||
</link>
|
||||
</internal>
|
||||
<external>
|
||||
<link>
|
||||
Trackers for :
|
||||
<a href="https://sourceforge.net/tracker/?group_id=76550&atid=547458">feature requests</a>,
|
||||
<a href="https://sourceforge.net/tracker/?group_id=76550&atid=547455">bugs</a> and
|
||||
<a href="https://sourceforge.net/tracker/?group_id=76550&atid=547457">patches</a>.
|
||||
</link>
|
||||
</external>
|
||||
<meta>
|
||||
<keywords>
|
||||
software development,
|
||||
computer programmer,
|
||||
php programming,
|
||||
programming php,
|
||||
software development company,
|
||||
software development uk,
|
||||
php tutorial,
|
||||
bespoke software development uk,
|
||||
corporate web development,
|
||||
architecture,
|
||||
freelancer,
|
||||
php resources,
|
||||
wordtracker,
|
||||
web marketing,
|
||||
serach engines,
|
||||
web positioning,
|
||||
internet marketing
|
||||
</keywords>
|
||||
</meta>
|
||||
</page>
|
|
@ -0,0 +1 @@
|
|||
1.1beta
|
237
vendor/swiftmailer/swiftmailer/test-suite/lib/simpletest/authentication.php
vendored
Normal file
237
vendor/swiftmailer/swiftmailer/test-suite/lib/simpletest/authentication.php
vendored
Normal file
|
@ -0,0 +1,237 @@
|
|||
<?php
|
||||
/**
|
||||
* Base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: authentication.php 1784 2008-04-26 13:07:14Z pp11 $
|
||||
*/
|
||||
/**
|
||||
* include http class
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/http.php');
|
||||
|
||||
/**
|
||||
* Represents a single security realm's identity.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleRealm {
|
||||
private $type;
|
||||
private $root;
|
||||
private $username;
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* Starts with the initial entry directory.
|
||||
* @param string $type Authentication type for this
|
||||
* realm. Only Basic authentication
|
||||
* is currently supported.
|
||||
* @param SimpleUrl $url Somewhere in realm.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleRealm($type, $url) {
|
||||
$this->type = $type;
|
||||
$this->root = $url->getBasePath();
|
||||
$this->username = false;
|
||||
$this->password = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another location to the realm.
|
||||
* @param SimpleUrl $url Somewhere in realm.
|
||||
* @access public
|
||||
*/
|
||||
function stretch($url) {
|
||||
$this->root = $this->getCommonPath($this->root, $url->getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the common starting path.
|
||||
* @param string $first Path to compare.
|
||||
* @param string $second Path to compare.
|
||||
* @return string Common directories.
|
||||
* @access private
|
||||
*/
|
||||
protected function getCommonPath($first, $second) {
|
||||
$first = explode('/', $first);
|
||||
$second = explode('/', $second);
|
||||
for ($i = 0; $i < min(count($first), count($second)); $i++) {
|
||||
if ($first[$i] != $second[$i]) {
|
||||
return implode('/', array_slice($first, 0, $i)) . '/';
|
||||
}
|
||||
}
|
||||
return implode('/', $first) . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identity to try within this realm.
|
||||
* @param string $username Username in authentication dialog.
|
||||
* @param string $username Password in authentication dialog.
|
||||
* @access public
|
||||
*/
|
||||
function setIdentity($username, $password) {
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current identity.
|
||||
* @return string Last succesful username.
|
||||
* @access public
|
||||
*/
|
||||
function getUsername() {
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for current identity.
|
||||
* @return string Last succesful password.
|
||||
* @access public
|
||||
*/
|
||||
function getPassword() {
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the URL is within the directory
|
||||
* tree of the realm.
|
||||
* @param SimpleUrl $url URL to test.
|
||||
* @return boolean True if subpath.
|
||||
* @access public
|
||||
*/
|
||||
function isWithin($url) {
|
||||
if ($this->isIn($this->root, $url->getBasePath())) {
|
||||
return true;
|
||||
}
|
||||
if ($this->isIn($this->root, $url->getBasePath() . $url->getPage() . '/')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if one string is a substring of
|
||||
* another.
|
||||
* @param string $part Small bit.
|
||||
* @param string $whole Big bit.
|
||||
* @return boolean True if the small bit is
|
||||
* in the big bit.
|
||||
* @access private
|
||||
*/
|
||||
protected function isIn($part, $whole) {
|
||||
return strpos($whole, $part) === 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages security realms.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleAuthenticator {
|
||||
private $realms;
|
||||
|
||||
/**
|
||||
* Clears the realms.
|
||||
* @access public
|
||||
*/
|
||||
function SimpleAuthenticator() {
|
||||
$this->restartSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts with no realms set up.
|
||||
* @access public
|
||||
*/
|
||||
function restartSession() {
|
||||
$this->realms = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new realm centered the current URL.
|
||||
* Browsers privatey wildly on their behaviour in this
|
||||
* regard. Mozilla ignores the realm and presents
|
||||
* only when challenged, wasting bandwidth. IE
|
||||
* just carries on presenting until a new challenge
|
||||
* occours. SimpleTest tries to follow the spirit of
|
||||
* the original standards committee and treats the
|
||||
* base URL as the root of a file tree shaped realm.
|
||||
* @param SimpleUrl $url Base of realm.
|
||||
* @param string $type Authentication type for this
|
||||
* realm. Only Basic authentication
|
||||
* is currently supported.
|
||||
* @param string $realm Name of realm.
|
||||
* @access public
|
||||
*/
|
||||
function addRealm($url, $type, $realm) {
|
||||
$this->realms[$url->getHost()][$realm] = new SimpleRealm($type, $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current identity to be presented
|
||||
* against that realm.
|
||||
* @param string $host Server hosting realm.
|
||||
* @param string $realm Name of realm.
|
||||
* @param string $username Username for realm.
|
||||
* @param string $password Password for realm.
|
||||
* @access public
|
||||
*/
|
||||
function setIdentityForRealm($host, $realm, $username, $password) {
|
||||
if (isset($this->realms[$host][$realm])) {
|
||||
$this->realms[$host][$realm]->setIdentity($username, $password);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the name of the realm by comparing URLs.
|
||||
* @param SimpleUrl $url URL to test.
|
||||
* @return SimpleRealm Name of realm.
|
||||
* @access private
|
||||
*/
|
||||
protected function findRealmFromUrl($url) {
|
||||
if (! isset($this->realms[$url->getHost()])) {
|
||||
return false;
|
||||
}
|
||||
foreach ($this->realms[$url->getHost()] as $name => $realm) {
|
||||
if ($realm->isWithin($url)) {
|
||||
return $realm;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents the appropriate headers for this location.
|
||||
* @param SimpleHttpRequest $request Request to modify.
|
||||
* @param SimpleUrl $url Base of realm.
|
||||
* @access public
|
||||
*/
|
||||
function addHeaders(&$request, $url) {
|
||||
if ($url->getUsername() && $url->getPassword()) {
|
||||
$username = $url->getUsername();
|
||||
$password = $url->getPassword();
|
||||
} elseif ($realm = $this->findRealmFromUrl($url)) {
|
||||
$username = $realm->getUsername();
|
||||
$password = $realm->getPassword();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
$this->addBasicHeaders($request, $username, $password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Presents the appropriate headers for this
|
||||
* location for basic authentication.
|
||||
* @param SimpleHttpRequest $request Request to modify.
|
||||
* @param string $username Username for realm.
|
||||
* @param string $password Password for realm.
|
||||
* @access public
|
||||
*/
|
||||
static function addBasicHeaders(&$request, $username, $password) {
|
||||
if ($username && $password) {
|
||||
$request->addHeaderLine(
|
||||
'Authorization: Basic ' . base64_encode("$username:$password"));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
/**
|
||||
* Autorunner which runs all tests cases found in a file
|
||||
* that includes this module.
|
||||
* @package SimpleTest
|
||||
* @version $Id: autorun.php 1809 2008-09-12 00:46:55Z lastcraft $
|
||||
*/
|
||||
require_once dirname(__FILE__) . '/unit_tester.php';
|
||||
require_once dirname(__FILE__) . '/mock_objects.php';
|
||||
require_once dirname(__FILE__) . '/collector.php';
|
||||
require_once dirname(__FILE__) . '/default_reporter.php';
|
||||
|
||||
$GLOBALS['SIMPLETEST_AUTORUNNER_INITIAL_CLASSES'] = get_declared_classes();
|
||||
register_shutdown_function('simpletest_autorun');
|
||||
|
||||
/**
|
||||
* Exit handler to run all recent test cases if no test has
|
||||
* so far been run. Uses the DefaultReporter which can have
|
||||
* it's output controlled with SimpleTest::prefer().
|
||||
*/
|
||||
function simpletest_autorun() {
|
||||
try {
|
||||
if (tests_have_run()) {
|
||||
return;
|
||||
}
|
||||
$candidates = array_intersect(
|
||||
capture_new_classes(),
|
||||
classes_defined_in_initial_file());
|
||||
$loader = new SimpleFileLoader();
|
||||
$suite = $loader->createSuiteFromClasses(
|
||||
basename(initial_file()),
|
||||
$loader->selectRunnableTests($candidates));
|
||||
$result = $suite->run(new DefaultReporter());
|
||||
} catch (Exception $stack_frame_fix) {
|
||||
print $stack_frame_fix->getMessage();
|
||||
$result = false;
|
||||
}
|
||||
if (SimpleReporter::inCli()) {
|
||||
exit($result ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current test context to see if a test has
|
||||
* ever been run.
|
||||
* @return boolean True if tests have run.
|
||||
*/
|
||||
function tests_have_run() {
|
||||
if ($context = SimpleTest::getContext()) {
|
||||
return (boolean)$context->getTest();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The first autorun file.
|
||||
* @return string Filename of first autorun script.
|
||||
*/
|
||||
function initial_file() {
|
||||
static $file = false;
|
||||
if (! $file) {
|
||||
if (isset($_SERVER, $_SERVER['SCRIPT_FILENAME'])) {
|
||||
$file = $_SERVER['SCRIPT_FILENAME'];
|
||||
} else {
|
||||
$included_files = get_included_files();
|
||||
$file = reset($included_files);
|
||||
}
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Just the classes from the first autorun script. May
|
||||
* get a few false positives, as it just does a regex based
|
||||
* on following the word "class".
|
||||
* @return array List of all possible classes in first
|
||||
* autorun script.
|
||||
*/
|
||||
function classes_defined_in_initial_file() {
|
||||
if (preg_match_all('/\bclass\s+(\w+)/i', file_get_contents(initial_file()), $matches)) {
|
||||
return array_map('strtolower', $matches[1]);
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Every class since the first autorun include. This
|
||||
* is safe enough if require_once() is alwyas used.
|
||||
* @return array Class names.
|
||||
*/
|
||||
function capture_new_classes() {
|
||||
global $SIMPLETEST_AUTORUNNER_INITIAL_CLASSES;
|
||||
return array_map('strtolower', array_diff(get_declared_classes(),
|
||||
$SIMPLETEST_AUTORUNNER_INITIAL_CLASSES ?
|
||||
$SIMPLETEST_AUTORUNNER_INITIAL_CLASSES : array()));
|
||||
}
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* This file contains the following classes: {@link SimpleCollector},
|
||||
* {@link SimplePatternCollector}.
|
||||
*
|
||||
* @author Travis Swicegood <development@domain51.com>
|
||||
* @package SimpleTest
|
||||
* @subpackage UnitTester
|
||||
* @version $Id: collector.php 1784 2008-04-26 13:07:14Z pp11 $
|
||||
*/
|
||||
|
||||
/**
|
||||
* The basic collector for {@link GroupTest}
|
||||
*
|
||||
* @see collect(), GroupTest::collect()
|
||||
* @package SimpleTest
|
||||
* @subpackage UnitTester
|
||||
*/
|
||||
class SimpleCollector {
|
||||
|
||||
/**
|
||||
* Strips off any kind of slash at the end so as to normalise the path.
|
||||
* @param string $path Path to normalise.
|
||||
* @return string Path without trailing slash.
|
||||
*/
|
||||
protected function removeTrailingSlash($path) {
|
||||
if (substr($path, -1) == DIRECTORY_SEPARATOR) {
|
||||
return substr($path, 0, -1);
|
||||
} elseif (substr($path, -1) == '/') {
|
||||
return substr($path, 0, -1);
|
||||
} else {
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the directory and adds what it can.
|
||||
* @param object $test Group test with {@link GroupTest::addTestFile()} method.
|
||||
* @param string $path Directory to scan.
|
||||
* @see _attemptToAdd()
|
||||
*/
|
||||
function collect(&$test, $path) {
|
||||
$path = $this->removeTrailingSlash($path);
|
||||
if ($handle = opendir($path)) {
|
||||
while (($entry = readdir($handle)) !== false) {
|
||||
if ($this->isHidden($entry)) {
|
||||
continue;
|
||||
}
|
||||
$this->handle($test, $path . DIRECTORY_SEPARATOR . $entry);
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method determines what should be done with a given file and adds
|
||||
* it via {@link GroupTest::addTestFile()} if necessary.
|
||||
*
|
||||
* This method should be overriden to provide custom matching criteria,
|
||||
* such as pattern matching, recursive matching, etc. For an example, see
|
||||
* {@link SimplePatternCollector::_handle()}.
|
||||
*
|
||||
* @param object $test Group test with {@link GroupTest::addTestFile()} method.
|
||||
* @param string $filename A filename as generated by {@link collect()}
|
||||
* @see collect()
|
||||
* @access protected
|
||||
*/
|
||||
protected function handle(&$test, $file) {
|
||||
if (is_dir($file)) {
|
||||
return;
|
||||
}
|
||||
$test->addFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests for hidden files so as to skip them. Currently
|
||||
* only tests for Unix hidden files.
|
||||
* @param string $filename Plain filename.
|
||||
* @return boolean True if hidden file.
|
||||
* @access private
|
||||
*/
|
||||
protected function isHidden($filename) {
|
||||
return strncmp($filename, '.', 1) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An extension to {@link SimpleCollector} that only adds files matching a
|
||||
* given pattern.
|
||||
*
|
||||
* @package SimpleTest
|
||||
* @subpackage UnitTester
|
||||
* @see SimpleCollector
|
||||
*/
|
||||
class SimplePatternCollector extends SimpleCollector {
|
||||
private $pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $pattern Perl compatible regex to test name against
|
||||
* See {@link http://us4.php.net/manual/en/reference.pcre.pattern.syntax.php PHP's PCRE}
|
||||
* for full documentation of valid pattern.s
|
||||
*/
|
||||
function __construct($pattern = '/php$/i') {
|
||||
$this->pattern = $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to add files that match a given pattern.
|
||||
*
|
||||
* @see SimpleCollector::_handle()
|
||||
* @param object $test Group test with {@link GroupTest::addTestFile()} method.
|
||||
* @param string $path Directory to scan.
|
||||
* @access protected
|
||||
*/
|
||||
protected function handle(&$test, $filename) {
|
||||
if (preg_match($this->pattern, $filename)) {
|
||||
parent::handle($test, $filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
/**
|
||||
* base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @version $Id: compatibility.php 1747 2008-04-13 18:26:47Z pp11 $
|
||||
*/
|
||||
|
||||
/**
|
||||
* Static methods for compatibility between different
|
||||
* PHP versions.
|
||||
* @package SimpleTest
|
||||
*/
|
||||
class SimpleTestCompatibility {
|
||||
|
||||
/**
|
||||
* Creates a copy whether in PHP5 or PHP4.
|
||||
* @param object $object Thing to copy.
|
||||
* @return object A copy.
|
||||
* @access public
|
||||
*/
|
||||
static function copy($object) {
|
||||
if (version_compare(phpversion(), '5') >= 0) {
|
||||
eval('$copy = clone $object;');
|
||||
return $copy;
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity test. Drops back to equality + types for PHP5
|
||||
* objects as the === operator counts as the
|
||||
* stronger reference constraint.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if identical.
|
||||
* @access public
|
||||
*/
|
||||
static function isIdentical($first, $second) {
|
||||
if (version_compare(phpversion(), '5') >= 0) {
|
||||
return SimpleTestCompatibility::isIdenticalType($first, $second);
|
||||
}
|
||||
if ($first != $second) {
|
||||
return false;
|
||||
}
|
||||
return ($first === $second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive type test.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if same type.
|
||||
* @access private
|
||||
*/
|
||||
protected static function isIdenticalType($first, $second) {
|
||||
if (gettype($first) != gettype($second)) {
|
||||
return false;
|
||||
}
|
||||
if (is_object($first) && is_object($second)) {
|
||||
if (get_class($first) != get_class($second)) {
|
||||
return false;
|
||||
}
|
||||
return SimpleTestCompatibility::isArrayOfIdenticalTypes(
|
||||
get_object_vars($first),
|
||||
get_object_vars($second));
|
||||
}
|
||||
if (is_array($first) && is_array($second)) {
|
||||
return SimpleTestCompatibility::isArrayOfIdenticalTypes($first, $second);
|
||||
}
|
||||
if ($first !== $second) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive type test for each element of an array.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if identical.
|
||||
* @access private
|
||||
*/
|
||||
protected static function isArrayOfIdenticalTypes($first, $second) {
|
||||
if (array_keys($first) != array_keys($second)) {
|
||||
return false;
|
||||
}
|
||||
foreach (array_keys($first) as $key) {
|
||||
$is_identical = SimpleTestCompatibility::isIdenticalType(
|
||||
$first[$key],
|
||||
$second[$key]);
|
||||
if (! $is_identical) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for two variables being aliases.
|
||||
* @param mixed $first Test subject.
|
||||
* @param mixed $second Comparison object.
|
||||
* @return boolean True if same.
|
||||
* @access public
|
||||
*/
|
||||
static function isReference(&$first, &$second) {
|
||||
if (version_compare(phpversion(), '5', '>=') && is_object($first)) {
|
||||
return ($first === $second);
|
||||
}
|
||||
if (is_object($first) && is_object($second)) {
|
||||
$id = uniqid("test");
|
||||
$first->$id = true;
|
||||
$is_ref = isset($second->$id);
|
||||
unset($first->$id);
|
||||
return $is_ref;
|
||||
}
|
||||
$temp = $first;
|
||||
$first = uniqid("test");
|
||||
$is_ref = ($first === $second);
|
||||
$first = $temp;
|
||||
return $is_ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if an object is a member of a
|
||||
* class hiearchy.
|
||||
* @param object $object Object to test.
|
||||
* @param string $class Root name of hiearchy.
|
||||
* @return boolean True if class in hiearchy.
|
||||
* @access public
|
||||
*/
|
||||
static function isA($object, $class) {
|
||||
if (version_compare(phpversion(), '5') >= 0) {
|
||||
if (! class_exists($class, false)) {
|
||||
if (function_exists('interface_exists')) {
|
||||
if (! interface_exists($class, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
eval("\$is_a = \$object instanceof $class;");
|
||||
return $is_a;
|
||||
}
|
||||
if (function_exists('is_a')) {
|
||||
return is_a($object, $class);
|
||||
}
|
||||
return ((strtolower($class) == get_class($object))
|
||||
or (is_subclass_of($object, $class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a socket timeout for each chunk.
|
||||
* @param resource $handle Socket handle.
|
||||
* @param integer $timeout Limit in seconds.
|
||||
* @access public
|
||||
*/
|
||||
static function setTimeout($handle, $timeout) {
|
||||
if (function_exists('stream_set_timeout')) {
|
||||
stream_set_timeout($handle, $timeout, 0);
|
||||
} elseif (function_exists('socket_set_timeout')) {
|
||||
socket_set_timeout($handle, $timeout, 0);
|
||||
} elseif (function_exists('set_socket_timeout')) {
|
||||
set_socket_timeout($handle, $timeout, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,380 @@
|
|||
<?php
|
||||
/**
|
||||
* Base include file for SimpleTest
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
* @version $Id: cookies.php 1784 2008-04-26 13:07:14Z pp11 $
|
||||
*/
|
||||
|
||||
/**#@+
|
||||
* include other SimpleTest class files
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/url.php');
|
||||
/**#@-*/
|
||||
|
||||
/**
|
||||
* Cookie data holder. Cookie rules are full of pretty
|
||||
* arbitary stuff. I have used...
|
||||
* http://wp.netscape.com/newsref/std/cookie_spec.html
|
||||
* http://www.cookiecentral.com/faq/
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleCookie {
|
||||
private $host;
|
||||
private $name;
|
||||
private $value;
|
||||
private $path;
|
||||
private $expiry;
|
||||
private $is_secure;
|
||||
|
||||
/**
|
||||
* Constructor. Sets the stored values.
|
||||
* @param string $name Cookie key.
|
||||
* @param string $value Value of cookie.
|
||||
* @param string $path Cookie path if not host wide.
|
||||
* @param string $expiry Expiry date as string.
|
||||
* @param boolean $is_secure Currently ignored.
|
||||
*/
|
||||
function __construct($name, $value = false, $path = false, $expiry = false, $is_secure = false) {
|
||||
$this->host = false;
|
||||
$this->name = $name;
|
||||
$this->value = $value;
|
||||
$this->path = ($path ? $this->fixPath($path) : "/");
|
||||
$this->expiry = false;
|
||||
if (is_string($expiry)) {
|
||||
$this->expiry = strtotime($expiry);
|
||||
} elseif (is_integer($expiry)) {
|
||||
$this->expiry = $expiry;
|
||||
}
|
||||
$this->is_secure = $is_secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host. The cookie rules determine
|
||||
* that the first two parts are taken for
|
||||
* certain TLDs and three for others. If the
|
||||
* new host does not match these rules then the
|
||||
* call will fail.
|
||||
* @param string $host New hostname.
|
||||
* @return boolean True if hostname is valid.
|
||||
* @access public
|
||||
*/
|
||||
function setHost($host) {
|
||||
if ($host = $this->truncateHost($host)) {
|
||||
$this->host = $host;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the truncated host to which this
|
||||
* cookie applies.
|
||||
* @return string Truncated hostname.
|
||||
* @access public
|
||||
*/
|
||||
function getHost() {
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for a cookie being valid for a host name.
|
||||
* @param string $host Host to test against.
|
||||
* @return boolean True if the cookie would be valid
|
||||
* here.
|
||||
*/
|
||||
function isValidHost($host) {
|
||||
return ($this->truncateHost($host) === $this->getHost());
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts just the domain part that determines a
|
||||
* cookie's host validity.
|
||||
* @param string $host Host name to truncate.
|
||||
* @return string Domain or false on a bad host.
|
||||
* @access private
|
||||
*/
|
||||
protected function truncateHost($host) {
|
||||
$tlds = SimpleUrl::getAllTopLevelDomains();
|
||||
if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) {
|
||||
return $matches[0];
|
||||
} elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) {
|
||||
return $matches[0];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for name.
|
||||
* @return string Cookie key.
|
||||
* @access public
|
||||
*/
|
||||
function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for value. A deleted cookie will
|
||||
* have an empty string for this.
|
||||
* @return string Cookie value.
|
||||
* @access public
|
||||
*/
|
||||
function getValue() {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for path.
|
||||
* @return string Valid cookie path.
|
||||
* @access public
|
||||
*/
|
||||
function getPath() {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a path to see if the cookie applies
|
||||
* there. The test path must be longer or
|
||||
* equal to the cookie path.
|
||||
* @param string $path Path to test against.
|
||||
* @return boolean True if cookie valid here.
|
||||
* @access public
|
||||
*/
|
||||
function isValidPath($path) {
|
||||
return (strncmp(
|
||||
$this->fixPath($path),
|
||||
$this->getPath(),
|
||||
strlen($this->getPath())) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for expiry.
|
||||
* @return string Expiry string.
|
||||
* @access public
|
||||
*/
|
||||
function getExpiry() {
|
||||
if (! $this->expiry) {
|
||||
return false;
|
||||
}
|
||||
return gmdate("D, d M Y H:i:s", $this->expiry) . " GMT";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if cookie is expired against
|
||||
* the cookie format time or timestamp.
|
||||
* Will give true for a session cookie.
|
||||
* @param integer/string $now Time to test against. Result
|
||||
* will be false if this time
|
||||
* is later than the cookie expiry.
|
||||
* Can be either a timestamp integer
|
||||
* or a cookie format date.
|
||||
* @access public
|
||||
*/
|
||||
function isExpired($now) {
|
||||
if (! $this->expiry) {
|
||||
return true;
|
||||
}
|
||||
if (is_string($now)) {
|
||||
$now = strtotime($now);
|
||||
}
|
||||
return ($this->expiry < $now);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ages the cookie by the specified number of
|
||||
* seconds.
|
||||
* @param integer $interval In seconds.
|
||||
* @public
|
||||
*/
|
||||
function agePrematurely($interval) {
|
||||
if ($this->expiry) {
|
||||
$this->expiry -= $interval;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor for the secure flag.
|
||||
* @return boolean True if cookie needs SSL.
|
||||
* @access public
|
||||
*/
|
||||
function isSecure() {
|
||||
return $this->is_secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a trailing and leading slash to the path
|
||||
* if missing.
|
||||
* @param string $path Path to fix.
|
||||
* @access private
|
||||
*/
|
||||
protected function fixPath($path) {
|
||||
if (substr($path, 0, 1) != '/') {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
if (substr($path, -1, 1) != '/') {
|
||||
$path .= '/';
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository for cookies. This stuff is a
|
||||
* tiny bit browser dependent.
|
||||
* @package SimpleTest
|
||||
* @subpackage WebTester
|
||||
*/
|
||||
class SimpleCookieJar {
|
||||
private $cookies;
|
||||
|
||||
/**
|
||||
* Constructor. Jar starts empty.
|
||||
* @access public
|
||||
*/
|
||||
function __construct() {
|
||||
$this->cookies = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes expired and temporary cookies as if
|
||||
* the browser was closed and re-opened.
|
||||
* @param string/integer $now Time to test expiry against.
|
||||
* @access public
|
||||
*/
|
||||
function restartSession($date = false) {
|
||||
$surviving_cookies = array();
|
||||
for ($i = 0; $i < count($this->cookies); $i++) {
|
||||
if (! $this->cookies[$i]->getValue()) {
|
||||
continue;
|
||||
}
|
||||
if (! $this->cookies[$i]->getExpiry()) {
|
||||
continue;
|
||||
}
|
||||
if ($date && $this->cookies[$i]->isExpired($date)) {
|
||||
continue;
|
||||
}
|
||||
$surviving_cookies[] = $this->cookies[$i];
|
||||
}
|
||||
$this->cookies = $surviving_cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ages all cookies in the cookie jar.
|
||||
* @param integer $interval The old session is moved
|
||||
* into the past by this number
|
||||
* of seconds. Cookies now over
|
||||
* age will be removed.
|
||||
* @access public
|
||||
*/
|
||||
function agePrematurely($interval) {
|
||||
for ($i = 0; $i < count($this->cookies); $i++) {
|
||||
$this->cookies[$i]->agePrematurely($interval);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an additional cookie. If a cookie has
|
||||
* the same name and path it is replaced.
|
||||
* @param string $name Cookie key.
|
||||
* @param string $value Value of cookie.
|
||||
* @param string $host Host upon which the cookie is valid.
|
||||
* @param string $path Cookie path if not host wide.
|
||||
* @param string $expiry Expiry date.
|
||||
* @access public
|
||||
*/
|
||||
function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
|
||||
$cookie = new SimpleCookie($name, $value, $path, $expiry);
|
||||
if ($host) {
|
||||
$cookie->setHost($host);
|
||||
}
|
||||
$this->cookies[$this->findFirstMatch($cookie)] = $cookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a matching cookie to write over or the
|
||||
* first empty slot if none.
|
||||
* @param SimpleCookie $cookie Cookie to write into jar.
|
||||
* @return integer Available slot.
|
||||
* @access private
|
||||
*/
|
||||
protected function findFirstMatch($cookie) {
|
||||
for ($i = 0; $i < count($this->cookies); $i++) {
|
||||
$is_match = $this->isMatch(
|
||||
$cookie,
|
||||
$this->cookies[$i]->getHost(),
|
||||
$this->cookies[$i]->getPath(),
|
||||
$this->cookies[$i]->getName());
|
||||
if ($is_match) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return count($this->cookies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the most specific cookie value from the
|
||||
* browser cookies. Looks for the longest path that
|
||||
* matches.
|
||||
* @param string $host Host to search.
|
||||
* @param string $path Applicable path.
|
||||
* @param string $name Name of cookie to read.
|
||||
* @return string False if not present, else the
|
||||
* value as a string.
|
||||
* @access public
|
||||
*/
|
||||
function getCookieValue($host, $path, $name) {
|
||||
$longest_path = '';
|
||||
foreach ($this->cookies as $cookie) {
|
||||
if ($this->isMatch($cookie, $host, $path, $name)) {
|
||||
if (strlen($cookie->getPath()) > strlen($longest_path)) {
|
||||
$value = $cookie->getValue();
|
||||
$longest_path = $cookie->getPath();
|
||||
}
|
||||
}
|
||||
}
|
||||
return (isset($value) ? $value : false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests cookie for matching against search
|
||||
* criteria.
|
||||
* @param SimpleTest $cookie Cookie to test.
|
||||
* @param string $host Host must match.
|
||||
* @param string $path Cookie path must be shorter than
|
||||
* this path.
|
||||
* @param string $name Name must match.
|
||||
* @return boolean True if matched.
|
||||
* @access private
|
||||
*/
|
||||
protected function isMatch($cookie, $host, $path, $name) {
|
||||
if ($cookie->getName() != $name) {
|
||||
return false;
|
||||
}
|
||||
if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) {
|
||||
return false;
|
||||
}
|
||||
if (! $cookie->isValidPath($path)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a URL to sift relevant cookies by host and
|
||||
* path. Results are list of strings of form "name=value".
|
||||
* @param SimpleUrl $url Url to select by.
|
||||
* @return array Valid name and value pairs.
|
||||
* @access public
|
||||
*/
|
||||
function selectAsPairs($url) {
|
||||
$pairs = array();
|
||||
foreach ($this->cookies as $cookie) {
|
||||
if ($this->isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) {
|
||||
$pairs[] = $cookie->getName() . '=' . $cookie->getValue();
|
||||
}
|
||||
}
|
||||
return $pairs;
|
||||
}
|
||||
}
|
||||
?>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue