-
Notifications
You must be signed in to change notification settings - Fork 24.3k
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
HTTP response headers with the same key are not processed properly. [The expected behaviour is that the values of the identical keys are combined to a string separated by a comma] #21795
Comments
I realised that if I introduce another variable to hold the headers key-value map in
} |
There seem to be something wonky about using WritableMap because every time it is queried to check if there is an existing key "if (responseHeaders.hasKey(headerName)) ", the result is always false even though the key was added previously which causes the else part to be executed and the previous value of the same key is overwritten with the new value. |
+1, very annoying issue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I have the same problem, when multiple set cookie headers are sent by the back end, we don't get to see them in the app- the system only shows the last one on Android. On ios we get them combined into one. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
I've also experienced this on Android. Multiple Set-Cookie headers seems to be the standard according to RFC-2109 section '4.2.1 Origin Server Role - General' as well as RFC-6265 section '3 Overview'. RFC-6265 explicitely states that:
I think we should conform to this standard as many frameworks already seem to. |
This comment has been minimized.
This comment has been minimized.
@mdloselo I think the bug as you said is in WritableNativeMap class. Looking at the code it keeps maps both in the C++ side and Java side, and they're not synced properly for every operation. Specifically If you already have the project checked out, can you call |
I think this issue is identical btw #18837 and the comments there also suggests the out of sync Java and C++ maps is the root cause. |
@hey99xx thanks, it works when I set |
@mdloselo I don't think Facebook lists all their changes in the public documentation website, they put minimal javadoc. You usually need to follow comments of core contributors to get an insight of what's coming next. In the master branch they moved mUseNativeAccessor to a slightly more visible ReactFeatureFlags class 4ac500a. I'd guess they're still unsure whether this change results in any perf imrovement and no regresssions (obviously not) so they still have both code paths available hidden behind a flag, that they can switch from their apps. I don't really know their plan since they seem to be running this experiment since 0.54. I think having bugs in their core map / array classes is a more serious issue and this HTTP headers bug is a very little symptom, this bug likely extends beyond networking. If anyone knows how to get traction from Facebook maintainers please do so. @ayc1 and @mdvacca have their names on the commit above so maybe they can help, also @hramos |
Is it possible to implement a simple HTTP client on Java to bypass fetch/xmlHttpRequest? |
I've tried upgrading our app from 0.53.3 to 0.55.4 and also hit this bug with multiple WWW-Authenticate headers which is allowed per RFC. iOS does not have the issue of only one header being sent on to the JS where as Android does. This is a serious issue. |
This is still an issue on Server code: <?php
header("X-Duplicate-Header: First entry");
header("X-Duplicate-Header: Second entry", false); RN client code: fetch(url)
.then(res => {
for (const entry of res.headers) {
console.log(`${entry[0]}: ${entry[1]}`);
}
}); Output:
Expected both "X-Duplicate-Header" header values as a comma delimited string, but only the last entry is available. As others, I encountered this issue when trying to authenticate to a web server that has multiple |
This comment has been minimized.
This comment has been minimized.
Anyone know if there are earlier versions of react-native that doesnt have this issue (multiple Cookies in response) for Android? |
0.53.3 is OK, I think this issue was introduced in 0.54. |
Works still 0.55.4. |
This comment has been minimized.
This comment has been minimized.
@rheng001 no, my comment marked as spam 😂😂 but suggested workarount does not work for me on product device 🤷♂️ Other solution does not exist yet, and spam marks does not help... |
@mxwiz I believe your comment was marked as outdated due to it referencing an older release at the time it was posted. |
@hramos maybe, but it is not fixed in newest versions. |
Hello, I had the same problem here and analysed the internal issue: The problem is a combination of react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java Lines 647 to 661 in 9895d01
That This flag defines if the ReadableNativeMap reads data from a native map or a internal (java.util.) HashMap. But the problem was that WritableNativeMap always writes into the native map and never uses the (Readable) internal HashMap. That was the reason why Like said by @hey99xx in #21795 (comment) and by @Return-1 #23005 (comment) its possible to activate the this native accessor, if you add this code to your own/project Add this imports: import com.facebook.react.bridge.ReadableNativeArray;
import com.facebook.react.bridge.ReadableNativeMap; And this add the beginning of the ReadableNativeArray.setUseNativeAccessor(true);
ReadableNativeMap.setUseNativeAccessor(true); For me this works fine. But notice that this global flag may cause some other troubles. I also started to fix this behaviour in the latest React Native 0.59.3 release, but notice than that the master version of ReadableNativeMap/WritableNativeMap was already changed. The commits b257e06 and a062b34 by FB eng @sahrens changed/removed the useNativeAccessor behaviour, so I hope this issue was also fixed with the next/upcoming minor release 0.60.0. 🙌 (I couldn't test the new version yet, because running from the npm package (also with sourcecode changes) works fine for me, but the sourcecode version of RN let fail some of my 3rd party libraries. I'm looking forward for a RC of 0.60.0 and maybe will update this text here then.) |
The way I read linked commits, |
I believe the issue is that Should be fixable though - if we only write to |
A temporary workaround might be to maintain your own parallel java map and check hasKey there. |
Could be implemented as a wrapper type that holds a WritableNativeMap inside it. |
Any update on this? The changes to |
This is literally unusable with express and express-session because of this issue |
@sahrens This issue still persists on 0.60.4, and the workaround doesn't work since you removed it. Please look into it, as it makes react native with cookie based auth unusable |
@sahrens I was looking at this and is there any reason why we couldn't juse use a standard Something like this:
|
Can we modify NetworkingModule.java file and temp fix in our projects ? |
@jeremywiebe @jerolimov fixing from the source seems to fix it. I made a release and you can try with |
#27066) Summary: Multiple `set-cookie` headers should be aggregated as one `set-cookie` with values in a comma separated list. It is working as expected on iOS but not on Android. On Android, only the last one is preserved The problem arises because `NetworkingModule.translateHeaders()` uses `WritableNativeMap` as the translated headers but uses both native and non-native methods. The mixup causes out of sync data that both sets of methods do no agree. A simple fix is to use `Bundle` as the storage and only convert it to `WritableMap` at the end in one go Related issues: #26280, #21795, #23185 ## Changelog [Android] [Fixed] - Fix multiple headers of the same name (e.g. `set-cookie`) not aggregated correctly Pull Request resolved: #27066 Test Plan: A mock api, https://demo6524373.mockable.io/, will return 2 `set-cookie` as follows: ``` set-cookie: cookie1=value1 set-cookie: cookie2=value2 ``` Verify the following will print the `set-cookie` with a value `cookie1=value1, cookie2=value2` ```javascript fetch('https://demo6524373.mockable.io/') .then(response => { console.log(response.headers); }); ``` On iOS, `set-cookie` will have `cookie1=value1, cookie2=value2` while on Android it will have `cookie2=value2` (preserving only the last one) Differential Revision: D18298933 Pulled By: cpojer fbshipit-source-id: ce53cd41d7c6de0469700617900f30a7d0914c26
#27066) Summary: Multiple `set-cookie` headers should be aggregated as one `set-cookie` with values in a comma separated list. It is working as expected on iOS but not on Android. On Android, only the last one is preserved The problem arises because `NetworkingModule.translateHeaders()` uses `WritableNativeMap` as the translated headers but uses both native and non-native methods. The mixup causes out of sync data that both sets of methods do no agree. A simple fix is to use `Bundle` as the storage and only convert it to `WritableMap` at the end in one go Related issues: #26280, #21795, #23185 ## Changelog [Android] [Fixed] - Fix multiple headers of the same name (e.g. `set-cookie`) not aggregated correctly Pull Request resolved: #27066 Test Plan: A mock api, https://demo6524373.mockable.io/, will return 2 `set-cookie` as follows: ``` set-cookie: cookie1=value1 set-cookie: cookie2=value2 ``` Verify the following will print the `set-cookie` with a value `cookie1=value1, cookie2=value2` ```javascript fetch('https://demo6524373.mockable.io/') .then(response => { console.log(response.headers); }); ``` On iOS, `set-cookie` will have `cookie1=value1, cookie2=value2` while on Android it will have `cookie2=value2` (preserving only the last one) Differential Revision: D18298933 Pulled By: cpojer fbshipit-source-id: ce53cd41d7c6de0469700617900f30a7d0914c26
…s (#27066) Summary: Multiple `set-cookie` headers should be aggregated as one `set-cookie` with values in a comma separated list. It is working as expected on iOS but not on Android. On Android, only the last one is preserved The problem arises because `NetworkingModule.translateHeaders()` uses `WritableNativeMap` as the translated headers but uses both native and non-native methods. The mixup causes out of sync data that both sets of methods do no agree. A simple fix is to use `Bundle` as the storage and only convert it to `WritableMap` at the end in one go Related issues: facebook/react-native#26280, facebook/react-native#21795, facebook/react-native#23185 ## Changelog [Android] [Fixed] - Fix multiple headers of the same name (e.g. `set-cookie`) not aggregated correctly Pull Request resolved: facebook/react-native#27066 Test Plan: A mock api, https://demo6524373.mockable.io/, will return 2 `set-cookie` as follows: ``` set-cookie: cookie1=value1 set-cookie: cookie2=value2 ``` Verify the following will print the `set-cookie` with a value `cookie1=value1, cookie2=value2` ```javascript fetch('https://demo6524373.mockable.io/') .then(response => { console.log(response.headers); }); ``` On iOS, `set-cookie` will have `cookie1=value1, cookie2=value2` while on Android it will have `cookie2=value2` (preserving only the last one) Differential Revision: D18298933 Pulled By: cpojer fbshipit-source-id: ce53cd41d7c6de0469700617900f30a7d0914c26
Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions. |
Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information. |
Environment
OS: macOS High Sierra 10.13.6
Node: 8.12.0
Yarn: Not Found
npm: 6.4.1
Watchman: 4.9.0
Xcode: Xcode 10.0 Build version 10A255
Android Studio: 3.2 AI-181.5540.7.32.5014246
Packages: (wanted => installed)
react: 16.3.1 => 16.3.1
react-native: https://github.com/expo/react-native/archive/sdk-30.0.0.tar.gz => 0.55.4
Description
I have an issue supporting multiple cookies passed on the response header on Android. I tracked the issue to
line 607
intranslateHeaders
function inNetworkingModule.java
file from the link below.https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
I debugged and realised that the code that checks if the headerMap of type
WritableMap
has the header key already in it is always failing and defaulting to the "Else" part which always replaces the previous key and value every time instead of combining previous key's value string separated by a comma as it is supposed to. Due to this, only one cookie is always passed to React side.Furthermore, the code I mentioned above use
ReadableNativeMap
class which holds the actual key-value map as an instance variable.getLocalMap
function inReadableNativeMap
class is used to retrieve the "mLocalMap" variable but always return an object that doesn't have values hence the code insideNetworkingModule
is not doing what it is supposed to.Lastly, I'm aware that my environment info state that I'm using react-native from Expo https://github.com/expo/react-native, however the code that I found an issue on, Expo also use it as is from https://github.com/facebook/react-native hence I created an issue here.
Reproducible Demo
Pass multiple headers with the same key from a network request.
In my case I'm getting response headers with multiple cookies with key "Set-Cookie" from a network request, but after it has been processed by the code I mentioned above, there is always one.
Sample response header with multiple cookies similar to what get from the server.
Server: Example Date: Tue, 16 Oct 2018 10:35:21 GMT Content-Type: application/json;charset=UTF-8 Connection: keep-alive Expires: 0 X-B3-TraceId: d6745404c1d2a7fb Set-Cookie: MyDBTokenForApps=6c785634-d62d-32a2-a4f7-8c1e0f42a93f; path=/; secure; Max-Age=43198; Expires=Tue, 16-Oct-2018 22:35:19 GMT Set-Cookie: anotherCookie=1$E4AAA5C9C37865158B02402AFFDB7856; path=/; domain=.example.co.za; secure X-XSS-Protection: 1; mode=block X-Frame-Options: DENY X-Content-Type-Options: nosniff Strict-Transport-Security: max-age=31536000 ; includeSubDomains Instance: /CSG/pool_vcoza_summer_80 10.112.205.215 80 Vary: Accept-Encoding Transfer-Encoding: chunked Cache-Control: public, max-age=0
After this has been processed by
translateHeaders
function, only one cookie header that was processed last remains.The text was updated successfully, but these errors were encountered: