Skip to content
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

Change WpNetworkHeaderMap to be a newtype for HashMap<String, Vec<String>> #500

Draft
wants to merge 1 commit into
base: change-header-map-type
Choose a base branch
from

Conversation

oguzkocer
Copy link
Contributor

This is a follow up to #490. As described in that PR, we are changing the exposed header map type to be HashMap<String, Vec<String>>. However, #490 doesn't change the inner type that we work with, leaving it as http::HeaderMap. Although there is some merit in using http::HeaderMap as our inner type, I don't think it outweighs the extra complexity of using 2 different types for the same thing. That's why this PR proposes converting WpNetworkHeaderMap to a new type for HashMap<String, Vec<String>>.

We still expose a function that converts this new type to http::HeaderMap, ensuring that Rust clients, including our integration test suite, can easily work with it.

The PR removes some unit tests that no longer make sense and adds a new one to validate that we are correctly parsing the number of pages. It also exposes additional fields for WpNetworkRequest so that Rust clients can use them without cloning the value - which wasn't an issue when using Arc<T>.

I believe there's still room for improvement in the request module, but as far as I can tell, this PR addresses our immediate needs. Any further improvements can be made in subsequent PRs.

@oguzkocer oguzkocer added this to the 0.2 milestone Jan 21, 2025
[
self.0.get(header_name),
self.0.get(&header_name.to_lowercase()),
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make an insensitive case comparison here, right? But this is not quite that? For example, header_value_as_u32("x-wp-total") returns none if the server uses HTTP1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the current implementation of using HeaderMap, since we no longer need to think about header names being case insensitive whenever reading from the "header map" type.

My thinking is we should stick with the HeaderMap internally in the library, but export the "header map" type as HashMap in the uniffi interface.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I think we should be able to implement Lift and Lower ourselves, instead of using the uniffi::Record macros, to expose HeaderMap directly as uniffi API. But that's probably a whole other topic to explore.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a separate type just to be able to handle things in a case insensitive way doesn't make sense to me. When we use two different types, we have to consider them both and just its extra mental load is not really worth it. Furthermore, converting http::HeaderMap is not a free operation and we don't get many benefits out of that cost anymore as we have to keep converting back and forth between requests and responses.

I'd have preferred if we could use http::HeaderMap everywhere, but if we can't do that, I'd prefer we use HashMap<String, Vec<String>> everywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, header_value_as_u32("x-wp-total") returns none if the server uses HTTP1.

Would you mind adding a failing test for this? I am probably missing something here because when I test it, it does seem to work with lowercase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant a new unit test. The new unit test passes for me locally and it seems like it passed in CI as well. Am I missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah.. the commit is not in this branch. I thought it might be the case after I commented, sorry about that. Let me take a look.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.. so, this doesn't work because we don't know the case of the original key. I just borrowed this from the link header lookup logic during the refactor and didn't pay attention to it afterwards.


I think there are some cases this is an issue even in current trunk, because Rust is not the only one who might do a lookup, so using http::HeaderMap doesn't completely fix the issue. For example, if we expose the keys such as X-WP-Total and then Kotlin or Swift does the lookup, there is no guarantee that they'll do it in a case-insensitive way.

The solution to this would be to use a key such as LowercaseString which is what http::HeaderName does under the hood, but the problem is that'd also require using uniffi::Object because otherwise we can't control its construction.

There is also unicase, but it has the same problem of requiring uniffi::Object.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, if we expose the keys such as X-WP-Total and then Kotlin or Swift does the lookup

IMHO, this issue is with Kotlin/Swift code. They should parse a string map using a proper HTTP header type, just as Rust should parse a string map using a proper HTTP header type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this issue is with Kotlin/Swift code

This stance is against what we are trying to do with the wordpress-rs project. Whenever possible, Rust layer is responsible for making sure that Kotlin/Swift code can't go wrong.


I have an idea but I am not sure if it'll work through the FFI layer. I'll test it in a few hours.

@crazytonyli
Copy link
Contributor

I have fixed CI issues in #489. Rebasing this PR should resolve the CI failures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants