webdevops / TYPO3-metaseo

TYPO3 MetaSEO Extension
https://typo3.org/extensions/repository/view/metaseo
GNU General Public License v3.0
38 stars 25 forks source link

Assets (Js, CSS) have wrong URL //typo3/typo3/... in Control Center #150

Closed thomaszbz closed 9 years ago

thomaszbz commented 9 years ago

Tested with:

Instead, prefix typo3/ is wrong here, as it's a relative path and the URL of the page which initiates the request of assets already has prefix http(s)://typo3/. Adding another prefix typo3/ results in http(s):typo3/typo3/ which will be 404'd by the web server.

Javascript console output:

GET http://172.17.0.48/typo3/index.php?route=%2Frecord%2Fedit&token=be5402aa313…aseoControlcenter%26moduleToken%3Dc2492bfc6bb759fcd81bad23408431521dc8ea80 500 (Internal Server Error)onclick @ index.php?M=MetaseoMetaseo_MetaseoControlcenter&moduleToken=c2492bfc6bb759fcd81bad23408431521dc8ea80:159
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:451 GET http://172.17.0.48/typo3/sysext/t3skin/icons/gfx/i/page 404 (Not Found)
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:451 GET http://172.17.0.48/typo3/sysext/t3skin/icons/gfx/i/page 404 (Not Found)
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:18 GET http://172.17.0.48/typo3/typo3/sysext/core/Resources/Public/JavaScript/Contrib/extjs/resources/css/ext-all-notheme.css 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:31 GET http://172.17.0.48/typo3/typo3/sysext/core/Resources/Public/JavaScript/Contrib/require.js 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:19 GET http://172.17.0.48/typo3/typo3/sysext/t3skin/extjs/xtheme-t3skin.css 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:38 GET http://172.17.0.48/typo3/typo3/sysext/core/Resources/Public/JavaScript/Contrib/extjs/adapter/ext-base-debug.js 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:32 GET http://172.17.0.48/typo3/typo3/sysext/core/Resources/Public/JavaScript/Contrib/jquery/jquery-2.1.4.js 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:39 GET http://172.17.0.48/typo3/typo3/sysext/core/Resources/Public/JavaScript/Contrib/extjs/ext-all-debug.js 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:49 GET http://172.17.0.48/typo3/typo3/sysext/lang/Resources/Public/JavaScript/Typo3Lang.js 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:40 GET http://172.17.0.48/typo3/typo3/sysext/core/Resources/Public/JavaScript/Contrib/extjs/locale/ext-lang-en.js 
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:35 Uncaught ReferenceError: jQuery is not defined(anonymous function) @ index.php?route=%2Frecord%    2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:35
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:44 Uncaught ReferenceError: Ext is not defined(anonymous function) @ index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:44
tree.js?1440464359:14 Uncaught ReferenceError: Ext is not defined(anonymous function) @ tree.js?1440464359:14
notifications.js?1440464359:14 Uncaught ReferenceError: Ext is not defined(anonymous function) @ notifications.js?1440464359:14
NameSpace.js?1440464360:24 Uncaught ReferenceError: Ext is not defined(anonymous function) @ NameSpace.js?1440464360:24
jsfunc.inline.js?1440464359:1325 Uncaught TypeError: $ is not a function(anonymous function) @ jsfunc.inline.js?1440464359:1325(anonymous function) @ jsfunc.inline.js?1440464359:1328
bootstrap.js?1440464359:20 Uncaught ReferenceError: jQuery is not defined(anonymous function) @ bootstrap.js?1440464359:20(anonymous function) @ bootstrap.js?1440464359:22
index.php?route=%2Frecord%2Fedit&token=be5402aa3133898aedb38304d895621c89cee35e&edit[tx_metaseo_set…:61 Uncaught TypeError: require is not a function

Investigation

Summary: Whenever TypoScriptFrontendController is instanciated it also instanciates PageRenderer (which is a Singleton!) and sets the backPath to typo3/ which is a change in behaviour which also affects URL creation of Backend Assets.

Affected Versions

This is a regression in TYPO3 CMS 7.4.0 introduced with commit 43ab6508e7eb01a5b9cca294257349d3e4a53995 https://review.typo3.org/#/c/41239/ https://review.typo3.org/#/c/41239/5/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php

Deprecation message does not include the breaking change we are faced with here. https://docs.typo3.org/typo3cms/extensions/core/latest/Changelog/7.4/Deprecation-68074-DeprecateGetPageRenderer.html

Forge issue

https://forge.typo3.org/issues/69319

thomaszbz commented 9 years ago

The reason for this to happen is that

TypoScriptFrontendController->initPageRenderer()

is somehow executed. This function makes a

protected function initPageRenderer() {
            //...
    $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
            //...
    $this->pageRenderer->setBackPath(TYPO3_mainDir);
}

with constant TYPO3_mainDir = 'typo3/'. So it sets a Frontend Backpath typo3/ which actually is responsible for this bug. A workaround would be to setBackPath(NULL), then everything works. But we can't do that of course in TYPO3's TypoScriptFrontendController.

When I throw an exception here (for a test):

protected function initPageRenderer() {
    $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
    if ((TYPO3_MODE == 'BE')) {
        throw new \Exception("You should not prefix assets with 'typo3/' in the Backend");
    }else{
        $this->pageRenderer->setBackPath(TYPO3_mainDir);
    }
}

then the exception gets thrown for the reproduction steps and I get the following stacktrace:

Exception: 'You should not prefix assets with 'typo3/' in the Backend'
Exception thrown in file
/var/webadmin/typo3_src/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php in line 913.

28 TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::initPageRenderer()

/var/webadmin/typo3_src/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php:
00889:   $this->uniqueString = md5(microtime());
00890:   $this->csConvObj = GeneralUtility::makeInstance(CharsetConverter::class);
> 00891:   $this->initPageRenderer();
00892:   // Call post processing function for constructor:
00893:   if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'])) {

27 TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::__construct(array, "1", 0, "", "", "", "", "")

/var/webadmin/typo3_src/typo3/sysext/core/Classes/Utility/GeneralUtility.php:
04351:     break;
04352:    case 9:
> 04353:     $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8]);
04354:     break;
04355:    default:

26 TYPO3\CMS\Core\Utility\GeneralUtility::instantiateClass("TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController", array)

/var/webadmin/typo3_src/typo3/sysext/core/Classes/Utility/GeneralUtility.php:
04309:   }
04310:   // Create new instance and call constructor with parameters
> 04311:   $instance = static::instantiateClass($finalClassName, func_get_args());
04312:   // Register new singleton instance
04313:   if ($instance instanceof SingletonInterface) {

25 TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance("TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController", array, "1", 0, "", "", "", "", "")
24 call_user_func_array(array, array)

/var/webadmin/typo3_src/typo3/sysext/extbase/Classes/Object/Container/Container.php:
00199:   $constructorArguments = $this->getConstructorArguments($className, $classInfo, $givenConstructorArguments);
00200:   array_unshift($constructorArguments, $className);
> 00201:   $instance = call_user_func_array(array(\TYPO3\CMS\Core\Utility\GeneralUtility::class, 'makeInstance'), $constructorArguments);
00202:   if ($classIsSingleton) {
00203:    $this->singletonInstances[$className] = $instance;

23 TYPO3\CMS\Extbase\Object\Container\Container::instanciateObject(TYPO3\CMS\Extbase\Object\Container\ClassInfo, array)

/var/webadmin/typo3_src/typo3/sysext/extbase/Classes/Object/Container/Container.php:
00172:    $this->prototypeObjectsWhichAreCurrentlyInstanciated[$className] = TRUE;
00173:   }
> 00174:   $instance = $this->instanciateObject($classInfo, $givenConstructorArguments);
00175:   $this->injectDependencies($instance, $classInfo);
00176:   $this->initializeObject($instance, $classInfo);

22 TYPO3\CMS\Extbase\Object\Container\Container::getInstanceInternal("TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController", array)

/var/webadmin/typo3_src/typo3/sysext/extbase/Classes/Object/Container/Container.php:
00119:  public function getInstance($className, $givenConstructorArguments = array()) {
00120:   $this->prototypeObjectsWhichAreCurrentlyInstanciated = array();
> 00121:   return $this->getInstanceInternal($className, $givenConstructorArguments);
00122:  }
00123: 

21 TYPO3\CMS\Extbase\Object\Container\Container::getInstance("TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController", array)

/var/webadmin/typo3_src/typo3/sysext/extbase/Classes/Object/ObjectManager.php:
00092:    $instance = call_user_func_array(array(\TYPO3\CMS\Core\Utility\GeneralUtility::class, 'makeInstance'), $arguments);
00093:   } else {
> 00094:    $instance = $this->objectContainer->getInstance($objectName, $arguments);
00095:   }
00096:   return $instance;

20 TYPO3\CMS\Extbase\Object\ObjectManager::get("TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController", array, "1", 0)

/var/www/typo3/typo3conf/ext/metaseo/Classes/Hook/TCA/RobotsTxtDefault.php:
00100:             $rootPageId,
00101:             0
> 00102:         );
00103: 
00104:         $GLOBALS['TSFE'] = $tsfeController;

19 Metaseo\Metaseo\Hook\TCA\RobotsTxtDefault::main(array, TYPO3\CMS\Backend\Form\FormEngine)
18 call_user_func_array(array, array)

/var/webadmin/typo3_src/typo3/sysext/core/Classes/Utility/GeneralUtility.php:
04172:      }
04173:      // Call method:
> 04174:      $content = call_user_func_array(array(&$classObj, $parts[1]), array(&$params, &$ref));
04175:     } else {
04176:      $errorMsg = 'No method name \'' . $parts[1] . '\' in class ' . $parts[0];

17 TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction("Metaseo\Metaseo\Hook\TCA\RobotsTxtDefault->main", array, TYPO3\CMS\Backend\Form\FormEngine)

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Form/Element/UserElement.php:
00044:    $parameterArray,
00045:    $dummyFormEngine
> 00046:   );
00047:   return $resultArray;
00048:  }

16 TYPO3\CMS\Backend\Form\Element\UserElement::render()

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php:
00180:    /** @var NodeFactory $nodeFactory */
00181:    $nodeFactory = $this->globalOptions['nodeFactory'];
> 00182:    $resultArray = $nodeFactory->create($options)->render();
00183:    $html = $resultArray['html'];
00184: 

15 TYPO3\CMS\Backend\Form\Container\SingleFieldContainer::render()

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Form/Container/PaletteAndSingleContainer.php:
00218:     /** @var NodeFactory $nodeFactory */
00219:     $nodeFactory = $this->globalOptions['nodeFactory'];
> 00220:     $singleFieldContentArray = $nodeFactory->create($options)->render();
00221: 
00222:     if (!empty($singleFieldContentArray['html'])) {

14 TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer::createPaletteContentArray("pallette_robotstxt")

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Form/Container/PaletteAndSingleContainer.php:
00117:    $fieldName = $fieldConfiguration['fieldName'];
00118:    if ($fieldName === '--palette--') {
> 00119:     $paletteElementArray = $this->createPaletteContentArray($fieldConfiguration['paletteName']);
00120:     if (!empty($paletteElementArray)) {
00121:      $mainStructureCounter ++;

13 TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer::render()

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Form/Container/TabsContainer.php:
00090:    /** @var NodeFactory $nodeFactory */
00091:    $nodeFactory = $this->globalOptions['nodeFactory'];
> 00092:    $childArray = $nodeFactory->create($options)->render();
00093: 
00094:    $tabsContent[] = array(

12 TYPO3\CMS\Backend\Form\Container\TabsContainer::render()

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Form/Container/FullRecordContainer.php:
00109:    /** @var NodeFactory $nodeFactory */
00110:    $nodeFactory = $this->globalOptions['nodeFactory'];
> 00111:    $resultArray = $nodeFactory->create($options)->render();
00112:   } else {
00113:    $options['renderType'] = 'noTabsContainer';

11 TYPO3\CMS\Backend\Form\Container\FullRecordContainer::render()

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Form/FormEngine.php:
00276:   $options = $this->getConfigurationOptionsForChildElements();
00277:   $options['renderType'] = 'fullRecordContainer';
> 00278:   $resultArray = $this->nodeFactory->create($options)->render();
00279: 
00280:   $content = $resultArray['html'];

10 TYPO3\CMS\Backend\Form\FormEngine::getMainFields("tx_metaseo_setting_root", array)

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Controller/EditDocumentController.php:
01073:           }
01074:          } else {
> 01075:           $panel .= $this->tceforms->getMainFields($table, $rec);
01076:          }
01077:          $panel = $this->tceforms->wrapTotal($panel, $rec, $table);

9 TYPO3\CMS\Backend\Controller\EditDocumentController::makeEditForm()

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Controller/EditDocumentController.php:
00873:    }
00874:    // Creating the editing form, wrap it with buttons, document selector etc.
> 00875:    $editForm = $this->makeEditForm();
00876:    if ($editForm) {
00877:     $this->firstEl = reset($this->elementsData);

8 TYPO3\CMS\Backend\Controller\EditDocumentController::main()

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Controller/EditDocumentController.php:
01663: 
> 01664:   $this->init();
01665:   $this->main();
01666: 
01667:   /** @var Response $response */

7 TYPO3\CMS\Backend\Controller\EditDocumentController::processRequest(TYPO3\CMS\Core\Http\ServerRequest)

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Http/RequestHandler.php:
00185:    throw new \RuntimeException('Requested controller "' . $className . '" does not implement the ControllerInterface', 1425389452);
00186:   }
> 00187:   return $controller->processRequest($request);
00188:  }
00189: }

6 TYPO3\CMS\Backend\Http\RequestHandler::dispatch(TYPO3\CMS\Core\Http\ServerRequest)

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Http/RequestHandler.php:
00090:   // Check if the router has the available route and dispatch.
00091:   if ($routingEnabled) {
> 00092:    return $this->dispatch($request);
00093:   }
00094: 

5 TYPO3\CMS\Backend\Http\RequestHandler::handleRequest(TYPO3\CMS\Core\Http\ServerRequest)

/var/webadmin/typo3_src/typo3/sysext/core/Classes/Core/Bootstrap.php:
00286: 
00287:   // Execute the command which returns a Response object or NULL
> 00288:   $this->response = $requestHandler->handleRequest($request);
00289:   return $this;
00290:  }

4 TYPO3\CMS\Core\Core\Bootstrap::handleRequest(TYPO3\CMS\Core\Http\ServerRequest)

/var/webadmin/typo3_src/typo3/sysext/backend/Classes/Http/Application.php:
00090:   */
00091:  public function run(callable $execute = NULL) {
> 00092:   $this->bootstrap->handleRequest($this->request);
00093: 
00094:   if ($execute !== NULL) {

3 TYPO3\CMS\Backend\Http\Application::run()

/var/webadmin/typo3_src/typo3/index.php:
00018: call_user_func(function() {
00019:  $classLoader = require __DIR__ . '/../vendor/autoload.php';
> 00020:  (new \TYPO3\CMS\Backend\Http\Application($classLoader))->run();
00021: });

2 {closure}()
1 call_user_func(Closure)

/var/webadmin/typo3_src/typo3/index.php:
00019:  $classLoader = require __DIR__ . '/../vendor/autoload.php';
00020:  (new \TYPO3\CMS\Backend\Http\Application($classLoader))->run();
> 00021: });
thomaszbz commented 9 years ago

According to the Stacktrace, the instanciation of TypoScriptFrontendcontroller is triggered by

Metaseo\Metaseo\Hook\TCA\RobotsTxtDefault::main(array, TYPO3\CMS\Backend\Form\FormEngine)
thomaszbz commented 9 years ago

Workaround

For instance, I'll reset the backPath to null after the use of TSFE has finished. That fixes it. This is a workaround for the regression in TYPO3 CMS.

/**
 * Sets backPath of PageRenderer back to null (for Backend)
 */
protected function cleanUpPageRendererBackPath()
{
    $pageRenderer = $this->getPageRenderer();
    $pageRenderer->setBackPath(null);
}