-
-
Notifications
You must be signed in to change notification settings - Fork 30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Application setHeader() does not respect $replace option #103
base: 2.0-dev
Are you sure you want to change the base?
Conversation
The setHeader() method causes the last header set to always be output even if $replace is set to false.
That is expected behaviour. After $app->setHeader('Some-Header', 'This should be used', true);
$app->setHeader('Some-Header', 'This should not be used', false); the value of the header is
which is intended. If you want to set a header only if it is not yet set, you need to check it separately. |
@nibra Why are all values not output then?
|
That depends on the actual header definition. Some accept multiple values, some don't. |
Correct, but currently multiple headers are just not output. Joomla 3 had some code to compose multiple headers into one single comma-separated line as they should, but that code does not seem to be in Joomla 4. Or are you saying that just because some cannot be composed, you decided to not output them to avoid the risk of an invalid one? |
@weeblr can you give me a link to where this code to compose multiple headers is found in Joomla 3? Then I see that we are setting the header here with required-> @weeblr when looking over this, it seems all is working as it should. Can you again go over the Laminas side of this, and see if your issue is not resolved taking their behavior into account? |
Problem is still there - although the code in WebApplication::setHeader() has changed since I made the PR a year ago. Just test it:
Problem is not in the Response object but in setHeader(). The logic is (still) wrong. I had a quick look and the buggy line is this one now:
It adds the (second) header to the response if
Which means the issue happens for any header name that's not on that Joomla hardcoded list of single value headers. My previous fix is still valid I guess:
|
Where do you see this I did not say that the issue is resolved, I said it could possible be because what you trying to do is being blocked at a lower level, and weakening the code here is not the best choice. |
Sorry, been nearly a year since opened this, wanted to reply to you quickly so I actually looked up and posted Joomla 3 stuff. First off, the issue is not solved. Please just test it. Paste this into any com_content template on Joomla 4.2.8:
and the Some-Header header is output with the "This should not be used value". Today. Joomla 4.2.8.
The setHeader() method does not behave according to its definition. It replaces an existing header when instructed not to do so. The second value should be appended to the first as CSV, and that does not happen. I looked quicky at how it's done inJ4 and the problem is indeed lower down, when rendering the headers, in j4/libraries/vendor/joomla/application/src/AbstractWebApplication.php at around line 630 in method sendHeaders. That method just iterate over the values and therefore always output the last one. In Joomla 3, the sendHeaders() method is in j3/libraries/src/Application/WebApplication.php, around line 800 and has code to correctly concatenate multiple headers, which has been removed from the J4 version. |
Therefore we should fix this getHeaders method instead, so that it will correctly deal with headers that have multiple values. |
Wondering why they did not just use this function |
This could be the fix:
@nibra or @HLeithner what do you think? |
How will we deal with this? https://github.com/laminas/laminas-diactoros/blob/2.2.2/src/MessageTrait.php#L164 |
I see the suggestive way of displaying this seems better:
|
Yes against all good practice Laminas uses a Trait to add these methods. |
This is what the "hardcoded list of single value headers" in Joomla 3 was doing. |
$singleValueResponseHeaders in /libraries/src/Application/WebApplication.php |
Simple question, why not set your header this way?
Then you can just do:
This seems to be how it should be done now, without any changes. Looking at the PSR7 documentation and the Laminas Diactoros Response class, the responsibility of setting the headers correctly does not belong to the application, but in fact belongs to the developer setting the header in the first place. Therefore, we should not hardcode Having said that, I assume that we have an intentional or none intentional limitation since the current AbstractWebApplication.php getHeaders method does not allow for multiple headers to be set the way your trying to set them. That is why I suggested the above workaround that actually gives you full control. |
Never assume you're in control. A website usually has many extensions, which can (will) often try to do the same thing. |
I hope they adopt the same approach as it is currently the correct way to set multiple values on a single header. Although I called it a workaround, it is essentially the only way to achieve this. The current application avoids the question of what should be single or multiple and instead forces all headers to be single unless explicitly set as multiple by the extension developer. This can be considered as a safeguard, as all headers that can be multiple can also be single, but not the other way around. Explicitly setting it as double/multiple indicates that the developer knows what they are doing, and the application does not need to assist them. |
That's not what I mean. One extension can set "Some-header" and another extension can also set "Some-header", unaware of what happened elsewhere. |
I will ask some of the other Maintainer to check my perspective, as I still feel the |
I think there's some confusion here:
Correct. Desired. The bug is that this is not what Joomla 4 is doing. This works in Joomla 3 but not in Joomla 4.
should result in
Currently, the result is:
That's just a flat out bug. |
Yes, you are correct. But this is always true, even if the application worked the way you wanted it to, and I understand that. When I said "you're in control," I meant to show that you have the ability to set the separator and not rely on the hard-coded |
Have you seen my previous message? your last reply is totally NOT what I am talking about and what this discussion is about. Again, this is a simple and straightforward bug. The setHeader() contract is fine and should not be changed. Simply Joomla 4 does not fulfill this contract. Passing false results in only the last header value being used, instead of all values being concatenated. |
Nope no confusion here :) Firstly the solution you gave will not be excepted as it does not fix the issue in the correct way. I already pointed you the function and possible fix in this comment. Have you tested that? Secondly I also explained why the current behavior though unintentional is proving to be a safe guard, that we may possible not change, but we may in fact update the contract, and remove the option of setting multiple values with the Please remember I am sitting on the other side of the world, and as you reply I am taking time to think of what you said and then reply with a smile. (sorry if it sounds off topic, I am just trying to explain myself best I can) I am like you here to help fix and improve the framework. |
I did not propose any solution, not sure what you are talking about. The initial code in that PR was for another context and since then abandonned. I had to dig through to find the real cause of the issue, described in this comment. The rest is all your doing. Again, I did not propose any solution, I am just asking that this function behaves per its current contract, as described by @nibra at the start. My current problem is that it does not.
So now you want to change the contract? introducing another BC break from Joomla 3?
I agree with that. Let's just have this method properly implements the behavior of this last boolean parameter. |
When I refer to "your proposed solution," I mean this current PR and the code contained within it (although I am aware that it is old). Today was the first time I read the PR and responded to it, with the aim of bringing it to a conclusion. I attempted to explain the underlying issue, which we can both agree is with the getHeaders method, and how it could possibly be resolved. Next, I tried to clarify why the getHeaders method appears to flatten the headers as a safeguard. While I can see the reasoning behind it, I also noted that I do not like the fact that it obviously breaks the contract and am unsure as to why this was done. However, I will obtain feedback from those who implemented it to ensure that we move forward without breaking any more things. The reality is that this has been broken for a while now, so the contract has already been breached. Today, after much research, I understood that there is indeed a bug, and your initial PR did try to fix it. But what I also found though, is that this bug appears to be intentional. For this reason, I am cautious about how we proceed with fixing it. Can you please test if this code:
Does indeed fix the issue? |
I don't see that, rather I don't see how it would be some sort of safeguard. What's the benefit? what's the problem solved? The only thing that does is making it impossible to output valid headers, where there are multiple values, without using the rather convoluted way of first reading the headers, then modifying them, then setting them. That - again - just looks like an oversight.
I don't see any reasoning. What would that be? what problem is this solving? *
I see no sign of intention here, just a bug. Think about it:
My intention is that this call will NOT replace any previously set value for this header, right? or else, I would not specificy the FALSE parameter. But currently, the effect is that sending TRUE or FALSE has the same result: any previously set value for this header is discarded. Surely that cannot be "intended". This is just something that was never implemented. |
Please update the PR with the fix I provided, also add a test for this issue, to ensure that we now have this issue resolved. @wilsonge have you had time to look at this? |
The setHeader() method causes the last header set to always be output even if $replace is set to false.
Summary of Changes
Incorrect use of $replace causes the last value for a given header to always override pre-existing values, even if $replace is set to false.
Testing Instructions
In any Joomla 4 version, use setHeader() similar to:
Currently, the "Some-Header" header is set to "This should not be used" instead of "This should be used".
Documentation Changes Required
None, bug fix.