Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
This issue was discovered while testing a rest service and the site was in offline (maintenance) mode.
If the site is in maintenance mode and if a 3rd party tries to access a service with "_format" query string mentioned, the response returned is not based on "_format" query string.
Steps to Replicate
- Setup a node that should be accessed by Web services.
- Put the site in maintenance mode.
- With a REST client try to access http://drupal8.dev/node/node-id?_format=hal_json
- Expected: JSON response should be displayed with maintenance message but returns the full theme with the maintenance message.
Proposed resolution
\Drupal\Core\EventSubscriber\MaintenanceModeSubscriber
should be aware of the requested response format.
Remaining tasks
- Write a patch.
- Add tests.
User interface changes
TBD
API changes
TBD
Comment | File | Size | Author |
---|---|---|---|
#78 | 2653318-78.patch | 5.39 KB | marthinal |
#78 | interdiff-2653318-74-78.txt | 1.73 KB | marthinal |
#74 | interdiff.txt | 961 bytes | dawehner |
#74 | 2653318-74.patch | 5.1 KB | dawehner |
#64 | rest_maintenance_mode-2653318-64.patch | 5.07 KB | aneek |
Comments
Comment #2
aneek CreditAttribution: aneek as a volunteer commentedComment #3
dawehnerYeah I guess we need to adapt
\Drupal\Core\EventSubscriber\MaintenanceModeSubscriber::onKernelRequestMaintenance
to support other formats as well.Comment #4
aneek CreditAttribution: aneek as a volunteer commented@dawehner,
I'll have a try then.
Comment #5
aneek CreditAttribution: aneek as a volunteer commentedComment #6
Wim Leers\Drupal\Core\EventSubscriber\MaintenanceModeSubscriber
doesn't live in the REST module\Drupal\Core\EventSubscriber\MaintenanceModeSubscriber
needs to be have better even when not using the REST module, but just using other formatsTherefore, moving to
.Comment #7
aneek CreditAttribution: aneek as a volunteer commented@Wim Leers, I believe, the logic can be to get the supplied "_format" in
\Drupal\Core\EventSubscriber\MaintenanceModeSubscriber::onKernelRequestMaintenance
and then call Serialization to respond back. But how to add serializer in MaintenanceModeSubscriber?Comment #8
Wim LeersHmm… interesting. That would not be possible, because that subscriber lives in core itself, but the
serializer
service lives in theserialization
module in core. If we'd indeed have to go that way… then the only way to do this would be to override theMaintenanceModeSubscriber
in theserialization
module, which feels very very inappropriate.Not sure yet how to solve this. Perhaps @dawehner or others have ideas.
Comment #9
aneek CreditAttribution: aneek as a volunteer commentedYes @WimLeers, that is the issue. Even if
serialization
module is not enabled then also the site should give proper json/xml response. But currently this will not happen. I tried with http://symfony.com/doc/current/components/serializer.html but was not working. May be I missed something. I'll give it another try!!But surely lets hear from others as well. I'll try to ping @dawehner tomorrow.
Comment #10
aneek CreditAttribution: aneek as a volunteer commentedComment #11
dawehnerWell, the idea world would be to return a MaintenanceMode domain object and then convert that to its appropriate response, but I think that kind of ship has sailed?
Maybe we want a dedicated listener for HTML and one for JSON?
Comment #12
aneek CreditAttribution: aneek as a volunteer commentedAdding a quick fix patch. It's just works as I tested manually. Needs review and hopefully a better fix!!. But we have to start from somewhere :-)
@dawehner & @WimLeers please suggest your thoughts on this.
Comment #13
aneek CreditAttribution: aneek as a volunteer commentedComment #14
Wim LeersI think #11 makes a lot of sense. Why do you think that wouldn't work anymore?
#12 is a step forward for core from an end user POV, but it's still going to be broken as soon as sites install modules that add support for more serialization formats. We should solve the generic problem, which is what #11 describes.
Comment #15
aneek CreditAttribution: aneek as a volunteer commented@WimLeers, that makes sense. Yes, the fix is a basic one and if other modules provide support for different types of serialization (like HATEOAS) then this might break.
Another idea is to return the MaintenanceMode domain object and convert it via Normalizer (maybe. ObjectNormalizer). Then expose the converted value to available serializations.
But how to? - Any ideas?
Comment #16
dawehnerWell, sadly we kinda dropped using that approach a while ago for Drupal itself, but sure, maybe reintroducing that here makes sense. On the other hand, for maintenance mode, we might want to return as early as possible, so that code would not work.
IMHO we don't really need a full serializer object for something we could just use
JsonResponse
Comment #17
aneek CreditAttribution: aneek as a volunteer commented@dawehner, I believe, the serializer objects are required since we also support XML as a valid format. Well, for JSON JsonResponse will do the job but for XML I think XmlEncoder is required.
Comment #19
aneek CreditAttribution: aneek as a volunteer commentedComment #20
Wim LeersMoving to
rest.module
for better visibility.Comment #21
dawehnerMh, it would be cool to override this service from within the serializer module, so it can use whatever format exists out there, by levering the serializer service.
Comment #22
aneek CreditAttribution: aneek as a volunteer commentedComment #23
Wim LeersAgreed. So, basically: any module that adds another serialization format is responsible for overriding the maintenance mode subscriber to provide maintenance mode support for that particular format.
Here's a patch that does that, mirrored after
\Drupal\Core\EventSubscriber\MaintenanceModeSubscriber
. Manual testing shows it works. Now this still needs test coverage.Assigning to damiankloip, because this is actually changing
serialization
module, which he is the maintainer of.Comment #24
dawehnerJust a general question, is is okay to initialize the serializer service now on every request?
Comment #25
Wim LeersWow, that's a great question!
The answer is of course: probably not. But… how to then fix this? Should we make
serializer
a lazy service?Comment #26
dawehnerAn alternative approach as talked with @damiankloip would be the following:
Throw a Maintenance mode exception.
Provide a exception handler which deals with HTML
Provide a exception handler for serializer.
Comment #27
klausiNote that REST services do not have to respond in the format the client requests, see the HTTP spec. The important thing a client must check is the status code: and that will be 500 while the site is in maintenance mode. Go fix your client to check status codes and do not rely on the response body when the status is 500.
Comment #28
Wim LeersBut… quoting yourself in #11:
Why would #26 be okay? It'd be breaking BC in some sense. Although perhaps this is not considered an actual/official API.
Comment #29
dawehnerThere are of course always alternative ways to implement things. For me conceptually, at this moment in time and space, maintenance mode is not the normal flow of things, but I agree we should avoid throwing exceptions if possible.
Well, event subscribers are certainly not an API, or are they?
Comment #30
Wim LeersDoes this mean this is a won't fix?
This answer sounds eminently sensible to me.
Comment #31
dawehnerIMHO its still odd that we return only HTML but I agree, clients have been always able to workaround it.
Comment #32
dawehnerThe question is whether clients should show it somehow that the sites is in maintenance mode or just guess based upon the status code.
Comment #33
Wim LeersIndeed. But … would they be able to parse
<response>The site is in maintenance mode…</response>
in a sane way in case of XML? They'd be expecting a completely differently structured response anyway.503 == "service unavailable" == maintenance mode, just without the friendly message. In case of REST, you need to provide your own friendly messages anyway.
So the more I think about it, the more klausi's point makes sense.
Comment #34
aneek CreditAttribution: aneek as a volunteer commented@WimLeers, I do get the point that you and @klausi trying to establish. And this is also true that a 3rd party should always check for the status code first then parse the response body. But is it a good approach to deliver a HTTP 503 with a HTML, CSS & JS based maintenance page when the 3rd party client requests for a xml or json response?
Also, yes 3rd party might not be expecting a
<response>The site is in maintenance mode…</response>
message as how could they know when the API server which they are using to consume services goes down. Correct!! But again, parsing the body while they get a 503 response. A simple XML with one parent or a JSON object is really easy to parse rather than a whole HTML content.Let me know your views on this regards.
Thanks!!
Comment #35
Wim Leers#34: I think it's fair to expect a REST API consumer to simply ignore the response body in case of a HTTP 5xx response. I think that if we do this, we don't do what I did in #23, where I put the site maintenance message in the response body. We just send an empty body: the 503 alone is sufficient.
Comment #36
dawehnerSo yeah what about providing a really simple implementation for now: For HTML return the HTML page, for everything else return
'text/plain'
with just the message?Comment #37
Wim Leers#36: I think that sounds eminently sensible, especially when considering #27:
Comment #38
dawehner#37 Yeah exactly, this was my idea. Sadly
"Giraffe"
is not valid JSON. This would have been even better.Comment #39
Wim LeersSo, something like this then.
Comment #41
Wim LeersI suck.
Comment #42
Wim LeersComment #43
dawehnerCould we move
into its own method?
Comment #44
Wim LeersI removed
Xss::filterAdmin()
… because#markup
gets that done automatically :) (See\Drupal\Core\Render\Renderer::ensureMarkupIsSafe()
.)Comment #45
dawehnerThis looks like a great solution for the problem. Now some simple non HTML tests would be nice.
Comment #46
Wim LeersDone. Test-only patch = interdiff.
Comment #48
Wim LeersI should've uploaded the FAIL patch first. My bad.
Comment #49
dawehnerCool
Comment #50
aneek CreditAttribution: aneek as a volunteer commentedThanks @dawehner & @WimLeers for contributing time in this issue. Manually tested and is working as expected.
Btw, a different thing that I've found,
If I put the site in maintenance mode, any pages or rest export made using views still is visible. The steps to replicate this issue is:
Do you guys think this is a valid case? I believe this is an issue and a major one :)
Comment #51
Wim Leers#50: that would be a separate problem. Please create a nee issue for that.
Comment #52
aneek CreditAttribution: aneek as a volunteer commented#51, yes done that #2732309: REST views ignore the maintenance mode setting
Comment #53
alexpottWhy's this outside the exempt check? I think it should be in it.
Comment #54
Wim LeersEh… you're absolutely right.
Comment #55
aneek CreditAttribution: aneek as a volunteer commentedA quick one :-)
Comment #56
aneek CreditAttribution: aneek as a volunteer commentedComment #58
aneek CreditAttribution: aneek as a volunteer commenteddawehner's patch from #2732309: REST views ignore the maintenance mode setting.
Comment #59
aneek CreditAttribution: aneek as a volunteer commentedComment #60
Wim LeersIt's confusing that two separate comments are now joined together.
Comment #61
aneek CreditAttribution: aneek as a volunteer commented@WimLeers: I am not too sure that I got your view point here. But, I think the last patch #15 from #2732309: REST views ignore the maintenance mode setting is for this ticket. So just applying that patch here.
Comment #62
Wim Leersaneek: I'm saying the changes you made in #55 are correct, but there should have been a blank line in between the comments.
Comment #63
aneek CreditAttribution: aneek as a volunteer commented@WimLeers: ahh.... :-)
Comment #64
aneek CreditAttribution: aneek as a volunteer commentedUploading a new one.
Comment #65
aneek CreditAttribution: aneek as a volunteer commentedComment #67
Wim Leers@aneek addressed the sole remark alexpott had in #53 over comments #54-#66. Restoring @dawehner's RTBC status from #49.
Comment #69
dawehnerLooks exactly like my patch :) And yes, I posted to the wrong issue ...
Comment #70
alexpottThis is failing and I think, but I'm not sure, might be part of another patch.
Comment #71
Wim LeersTrue, see #50 + #52. #58 brought the fix to this issue. It feels like it's within scope, because it's again about REST responses + maintenance mode. However, if you really want, we could split that off to #2732309: REST views ignore the maintenance mode setting.
And it definitely used to pass :( Queued for re-testing.
Comment #73
Wim LeersFailed again. I wonder what changed in REST views code or elsewhere that is causing this to now fail?
Comment #74
dawehnerThis particular subset of the test never worked, see #55 and following.
What happens is the following:
Questions:
\Drupal\system\Form\SiteMaintenanceModeForm::submitForm
?Comment #75
Wim Leers#2453351: Maintenance mode message ends up in page cache, served endlessly ensured that nothing ends up in page cache while maintenance mode is on.
But it looks like maintenance mode is designed to NOT prevent page cache from working completely; it seems it's designed to still let cached pages for anonymous users (either in Page Cache or in Varnish). That actually makes sense: if anonymous responses are cached in Page Cache/Varnish… which means that end users can continue to see sensible output… then why would we force them to see a maintenance message?
Because it must be treated the same way as any other reverse proxy, such as Varnish.
So, as far as I'm concerned, the problem is that the additions to
StyleSerializerTest
are happening after PageCache has been filled. It should test PageCache behavior before PageCache has been filled, because once filled, it's intentional that users get to see the cached responses.Comment #76
alexpott+1 to #75 - yes we should show users cached pages if we have them.
Comment #77
Wim LeersSo then #74 is wrong. Discussed with @dawehner: let's move that test into a separate test method, so that it runs in a unique environment, i.e. with a cold page cache.
Comment #78
marthinal CreditAttribution: marthinal commentedAdding a new method.
Comment #79
Wim LeersComment #80
alexpottCommitted f692cd0 and pushed to 8.1.x and 8.2.x. Thanks!
I don't think MaintenanceModeSubscriber should be considered API therefore adding a protected method to solve a bug is fine in a patch release.
Remove unused use on commit.