Problem/Motivation
I have installed the module simple access log to log any request made to drupal. This module intercepts the event kernel.request via event subscriber to extract request information to save it on the database.
However when a batch process is launched, the request is broken because this event subscriber tries to get the title of the batch page calling \Drupal::service('title_resolver')->getTitle($request, $route), which on turn calls Drupal\system\Controller\BatchController::batchPageTitle(), and this method try to call the function _batch_current_set, but the file core/includes/batch.inc that contains this function is not loaded yet, causing the next error:
The website encountered an unexpected error. Please try again later.
Error: Call to undefined function Drupal\system\Controller\_batch_current_set() in Drupal\system\Controller\BatchController->batchPageTitle() (line 92 of core/modules/system/src/Controller/BatchController.php).
Drupal\system\Controller\BatchController->batchPageTitle()
call_user_func_array(Array, Array) (Line: 58)
Drupal\Core\Controller\TitleResolver->getTitle(Object, Object) (Line: 82)
Drupal\simple_access_log\Controller\SimpleAccessLog->logValues() (Line: 25)
Drupal\simple_access_log\EventSubscriber\SimpleAccessLogSubscriber->executeLogFunction(Object, ‘kernel.request’, Object)
call_user_func(Array, Object, ‘kernel.request’, Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(‘kernel.request’, Object) (Line: 127)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 67)
Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 49)
Asm89\Stack\Cors->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 693)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
Everything seems to indicate that it is assumed that this file is already loaded when before executing this method.
Steps to reproduce
To reproduce this bug with Drupal core alone, enable the block module, place the breadcrumb block for your theme, and visit the /batch/anything path, where anything is any string.
Proposed resolution
Include the file required before calling _batch_current_set() as the method batchPage does, or check if the function exists before calling it.
| Comment | File | Size | Author |
|---|---|---|---|
| #29 | 3083106-29.patch | 3.98 KB | mfb |
Comments
Comment #2
dogamboar commentedI add the patch with the proposed solution to include the file "/core/includes/batch.inc" in the batchPageTitle method as it is done in the batchPage method.
Comment #3
dogamboar commentedSorry, after more testing, the last patch I sent does not work in the batch workflow. Apparently the order in which certain methods are called within the batch.in file alter their result after when the batch page is processed. Needs work.
Comment #4
dogamboar commentedI include a new patch with another approach to handle the event error in which the batch file has not yet been loaded.
Comment #7
demonde commentedSame error, patch in #4 helps.
Comment #10
mfbAdding steps to reproduce the bug on Drupal core without any other modules installed.
Comment #11
mfbHere's a test-only patch (should fail). To reproduce the bug, I had to add block module and enable the breadcrumb block. Could be done in a separate test class if preferred.
Comment #13
mfbComment #16
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
Re-triggering for 10.1 and 9.5.x tests but don't expect failures
Followed the steps in the IS and can confirm the issue
Patch does fix the issue
Comment #17
alexpottThe test being added here is kinda of incorrect. Batches are never requested at /batch/something - they are requested at /batch?id=12
Also the fix for the breadcrumbs is different than for the bug reported in the issue summary. We're never really going to have a breadcrumb for /batch so we should be exlcuding it like we do /user. I.e in \Drupal\system\PathBasedBreadcrumbBuilder::build() we could do something like:
But I think this issue points to a need to add a route option to disable the breadcrumb - that way contrib could make a similar fix. This probably should be split out into a separate fix.
So thinking about the original issue. The problem is you're not going to log the correct title with the current fix because in order to do that you need to load the batch. I think we need to do something like:
I.e
Comment #18
mfbOk let's see if that passes tests.
Comment #19
alexpottWe should change this test. We should be getting the title for route like /batch?id=1234124123 ... we'll have to create a request and route match object to pass to the title resolver - see how \Drupal\system\PathBasedBreadcrumbBuilder::build() does it.
Comment #20
mfbis it enough to just call the broken method in a test, like this?
If not, then yeah the test could call
\Drupal::service('title_resolver')->getTitle($request, $route)as per the original issue summary.For the record, I actually hit this bug as per the test I originally wrote - via an automated pentesting bot hitting random bogus paths including batch/[some string] - which tried and failed to build the breadcrumb.
Comment #21
alexpott@mfb so we need to fix the path breadcrumb builder issue in a separate related issue because even with this fix the breadcrumbs on batch/some_nonsense is incorrect. I think the test in #20 is okay - I think what'd be really nice is a unit test that tests getting the batch from storage (using a mock). Also we need to inject the batch storage service into the class.
Comment #22
alexpottTHis part of #21
Is something we should do on this issue. We also need to open another issue about excluding paths from the breadcrumb builder.
Comment #23
mfbDid a bit more work on this - now injecting the service, and changed test from kernel test to unit test. But for the latter to work, I had to require form.inc, otherwise function batch_get() does not exist.
Comment #24
alexpottNice. So we should also test that a title is returned when batch_get() returns something. TO do this we can mock the load method on the batch storage.
Also as we're loading code and changing the state of the system let's add the @runTestsInSeparateProcesses annotation to the test class.
Comment #25
alexpottI opened the related issue - #3344200: PathBasedBreadcrumbBuilder needs to be able to exclude pointless paths
Comment #26
mfbThis seems to work as a minimal mock batch array
Comment #27
smustgrave commentedSeems #25 have been addressed in
+ $this->assertSame('foobar', $controller->batchPageTitle(new Request(['id' => 1234])));
This looks good. Adding 3344200 to my list also.
Comment #28
alexpottThis test should cover both situations - where the batch exists and where it does not.
Comment #29
mfbAdded another test case in there too - batch could be returned by &batch_get()
Comment #30
smustgrave commentedGoing to try it again. If it's wrong I do apologize!
Comment #31
alexpottGiven the constructor changes I think we can only commit this fix to 10.1.x - I considered asking for the deprecation dance and allow a NULL for batch storage but there's nothing in contrib that extends this class so I think we fine.
Committed cdd8b0522b and pushed to 10.1.x. Thanks!
Slightly improved the test on commit.