Closed
Bug 1403802
Opened 7 years ago
Closed 7 years ago
Rewrite PrepareAcceptLanguages with modern nsCString API
Categories
(Core :: Networking, enhancement, P5)
Core
Networking
Tracking
()
RESOLVED
FIXED
mozilla58
Tracking | Status | |
---|---|---|
firefox58 | --- | fixed |
People
(Reporter: schien, Assigned: jthemphill, Mentored)
Details
(Keywords: good-first-bug, Whiteboard: [necko-triaged])
Attachments
(1 file, 5 obsolete files)
(deleted),
patch
|
valentin
:
review+
|
Details | Diff | Splinter Review |
|PrepareAcceptLanguages| can be rewrite with modern nsCString API to avoid false alarm in cppcheck linter, as mentioned in bug 1372065 comment #1.
Here is the TODO list:
- avoid unecessary string copy
- use nsCCharSeparatedTokenizer as the string tokenizer
- use nsTString::Trim to replace the usage of net_FindCharInSet and net_FindCharNotInSet
Comment 1•7 years ago
|
||
It might also be appropriate to use rust for the method rewrite.
Updated•7 years ago
|
Whiteboard: necko-triaged
Updated•7 years ago
|
Whiteboard: necko-triaged → [necko-triaged]
Assignee | ||
Comment 2•7 years ago
|
||
I'm willing to take this bug on. Here's a sample patch. Two major questions I have (notwithstanding problems in the code):
1. I haven't written a gtest, nor have I run the full test suite. When I try to run `./mach gtest netwerk`, I get this error:
```
1:46.09 In file included from /Users/jhemphill/oss/firefox/obj-x86_64-apple-darwin16.7.0/dom/file/Unified_cpp_dom_file0.cpp:110:
1:46.09 /Users/jhemphill/oss/firefox/dom/file/MutableBlobStorage.cpp:10:10: fatal error: 'mozilla/dom/ipc/TemporaryIPCBlobChild.h' file not found
1:46.09 #include "mozilla/dom/ipc/TemporaryIPCBlobChild.h"
1:46.09 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1:46.25 1 error generated.
```
I'm rebased onto the tip of the source tree (71a2dacbbb8ba2f3522432ff7e8fc0151ca591f9). Does this mean trunk is broken? How do I find a commit on which gtest will work?
2. I'm willing to rewrite this logic in Rust, but I'm not sure how you want to handle migrating code to Rust. Should I start a crate directly in the netwerk directory? Or should I create an external crate, then set that crate as a dependency? It seems like overkill, since PrepareAcceptLanguages is just a private helper function. But maybe it will be easier to move more code in once we have the infrastructure.
Attachment #8916339 -
Flags: review+
Assignee | ||
Updated•7 years ago
|
Attachment #8916339 -
Flags: review+ → review?(schien)
Comment 3•7 years ago
|
||
> 2. I'm willing to rewrite this logic in Rust, but I'm not sure how you want
> to handle migrating code to Rust. Should I start a crate directly in the
> netwerk directory? Or should I create an external crate, then set that crate
> as a dependency? It seems like overkill, since PrepareAcceptLanguages is
> just a private helper function. But maybe it will be easier to move more
> code in once we have the infrastructure.
I imagine it would look something like a new crate in netwerk/base called rust_helper (or something similar)
Then add a header and .rs implementation similar to rust-url-capi
The rust implementation should avoid performing any temporary allocations.
The signatures would look something similar to:
#[no_mangle]
pub extern "C" fn PrepareAcceptLanguages(iAcceptLanguages: &nsACString, oAcceptLanguages: &mut nsACString) -> nsresult
#[no_mangle]
pub extern "C" fn CanonicalizeLanguageTag(languageTag: &mut nsACString)
Assignee | ||
Updated•7 years ago
|
Attachment #8916339 -
Flags: review?(schien) → review-
Reporter | ||
Comment 4•7 years ago
|
||
I'd like to see more necko code move to rust. @valentin can you be the mentor? since you have more experience on rust.
For testing this modification, I'll suggest using xpcshell test instead of gtest.
By changing the "intl.accept_languages" preference you can hit the AcceptLanguage generation. Verify the request header in next HTTP request like https://searchfox.org/mozilla-central/source/services/common/tests/unit/test_hawkrequest.js#47
Flags: needinfo?(valentin.gosu)
Comment 5•7 years ago
|
||
(In reply to Shih-Chiang Chien [:schien] (UTC+8) (use ni? plz) from comment #4)
> I'd like to see more necko code move to rust. @valentin can you be the
> mentor? since you have more experience on rust.
Sure.
Mentor: schien → valentin.gosu
Flags: needinfo?(valentin.gosu)
Assignee | ||
Comment 6•7 years ago
|
||
Here's what I have so far. The individual units compile, and the Rust crate passes its own tests, but everything fails at the linker step. Which is fair, since I don't know how to link the C++ files to the Rust files.
I've tried to decipher the moz.build scripts, but I'm still not sure what is being built, or how we distinguish between .cpp files and .o files. Also not sure what the compilation units are. When I type `./mach build netwerk`, what does it build? Is it a giant netwerk.o library? Is moz.build a replacement for Make, or does it generate a Makefile, and if so, how?
I see a bunch of Rust stuff in toolkit/library/shared/rust. Do we just add Rust crates there, since whatever arcane stuff we need to do is already done there?
Attachment #8916339 -
Attachment is obsolete: true
Flags: needinfo?(valentin.gosu)
Comment 7•7 years ago
|
||
(In reply to jthemphill from comment #6)
> Created attachment 8918515 [details]
> How do I link C++ to a new Rust Crate?
>
> Here's what I have so far. The individual units compile, and the Rust crate
> passes its own tests, but everything fails at the linker step. Which is
> fair, since I don't know how to link the C++ files to the Rust files.
Take a look at this:
https://developer.mozilla.org/en-US/Firefox/Building_Firefox_with_Rust_code#Adding_Rust_code
> I've tried to decipher the moz.build scripts, but I'm still not sure what is
> being built, or how we distinguish between .cpp files and .o files. Also not
> sure what the compilation units are. When I type `./mach build netwerk`,
> what does it build? Is it a giant netwerk.o library? Is moz.build a
> replacement for Make, or does it generate a Makefile, and if so, how?
It's a very complicated build system that I don't fully understand, but you shouldn't need to deal with that right now.
> I see a bunch of Rust stuff in toolkit/library/shared/rust. Do we just add
> Rust crates there, since whatever arcane stuff we need to do is already done
> there?
Pretty much, yes. The rust code should live in each their appropriate folder (in this case netwerk/ ) but it should referenced as stated in the link above, so it's linked into the same library.
Flags: needinfo?(valentin.gosu)
Assignee | ||
Comment 8•7 years ago
|
||
Ah, okay. I was trying to run a partial build with `./mach build netwerk`, but apparently I have to run a full build, every time. Anyway, the code is actually ready for review now.
Attachment #8918515 -
Attachment is obsolete: true
Attachment #8918735 -
Flags: review?(valentin.gosu)
Comment 9•7 years ago
|
||
Comment on attachment 8918735 [details] [diff] [review]
ready-for-review.hgpatch
Review of attachment 8918735 [details] [diff] [review]:
-----------------------------------------------------------------
This looks quite good. Just a few changes necessary from my point of view.
For the next version we should ask nfroyd@mozilla.com for review as well - he's a Rust module peer.
::: netwerk/base/rust-helper/src/lib.rs
@@ +1,3 @@
> +static HTTP_LWS: &'static [u8] = &[' ' as u8, '\t' as u8];
> +
> +pub mod protocol;
Place all the code into this file. There's no need to over-complicate this.
::: netwerk/base/rust-helper/src/protocol/http/mod.rs
@@ +1,1 @@
> +pub mod nshttphandler;
This file should not exist.
::: netwerk/base/rust-helper/src/protocol/http/nshttphandler.rs
@@ +1,1 @@
> +use HTTP_LWS;
This code should be in lib.rs
@@ +26,5 @@
> +}
> +
> +#[no_mangle]
> +#[allow(non_snake_case)]
> +/// Allocates a C string into that contains a ISO 639 language list
This comment is wrong. It doesn't technically an C string, it creates an nsACString.
@@ +128,5 @@
> + }
> + let sub_tag_len = sub_tag.len();
> +
> + if sub_tag_len == 1 {
> + // x
x?
::: netwerk/base/rust-helper/src/protocol/http/rust-nsHttpHandler.h
@@ +1,1 @@
> +#ifndef RUST_NS_HTTP_HANDLER
move this to netwerk/base/rust-helper/src/helper.h or something similar in that same folder.
Also call the define something more generic RUST_NS_NET_HELPER ?
::: netwerk/base/rust-helper/src/protocol/mod.rs
@@ +1,1 @@
> +pub mod http;
This file should not exist.
::: netwerk/protocol/http/nsHttpHandler.cpp
@@ +58,4 @@
> #include "nsIXULRuntime.h"
> #include "nsCharSeparatedTokenizer.h"
> #include "nsRFPService.h"
> +#include "rust-helper/src/protocol/http/rust-nsHttpHandler.h"
This would then be rust-helper/src/helper.h
@@ +1907,4 @@
> if (!i_AcceptLanguages)
> return NS_OK;
>
> + const nsCString ns_accept_languages(i_AcceptLanguages);
instead of nsCString use nsAutoCString acceptLanguages(i_AcceptLanguages)
Attachment #8918735 -
Flags: review?(valentin.gosu) → feedback+
Assignee | ||
Comment 10•7 years ago
|
||
Hm, okay. I structured the crate with the intention that more code would be added, and that we'd want to keep the submodules, header files, etc. organized accordingly. But I'll assume YAGNI and keep it simple for this bug :)
Assignee | ||
Comment 11•7 years ago
|
||
Attachment #8918735 -
Attachment is obsolete: true
Attachment #8920442 -
Flags: review?(nfroyd)
Assignee | ||
Comment 12•7 years ago
|
||
According to xpcom/rust/nsstring/src/lib.rs:
//! Use `ns[C]String` (`ns[C]String` in C++) for string struct members, and as
//! an intermediate between rust string data structures (such as `String` or
//! `Vec<u16>`) and `&{mut,} nsA[C]String` (using `ns[C]String::from(value)`).
//! These conversions will attempt to re-use the passed-in buffer, appending a
//! null.
//!
//! ...
//!
//! There is currently no Rust equivalent to nsAuto[C]String. Implementing a
//! type that contains a pointer to an inline buffer is difficult in Rust due
//! to its move semantics, which require that it be safe to move a value by
//! copying its bits. If such a type is genuinely needed at some point,
//! https://bugzilla.mozilla.org/show_bug.cgi?id=1403506#c6 has a sketch of how
//! to emulate it via macros.
So how does nsAutoCString work here?
Flags: needinfo?(valentin.gosu)
Assignee | ||
Comment 13•7 years ago
|
||
Nevermind, I get it. Rust can only interact with the nsAString proxy object, so it never has a chance to screw up the internals of an nsAutoString. But we can't build an nsAutoString inside Rust without some ridiculous unsafeness.
Flags: needinfo?(valentin.gosu)
Comment 14•7 years ago
|
||
Comment on attachment 8920442 [details] [diff] [review]
Need second opinion from nfroyd
Review of attachment 8920442 [details] [diff] [review]:
-----------------------------------------------------------------
This is very cool! Incrementally moving some pretty gross C code to Rust is fantastic!
Just two small things to note.
::: netwerk/base/rust-helper/src/lib.rs
@@ +69,5 @@
> + let o_token = o_accept_languages.to_mut();
> + canonicalize_language_tag(&mut o_token[token_pos..]);
> + }
> +
> +
Nit: we can remove a blank line here.
@@ +125,5 @@
> + }
> +
> + let sub_tag_len = sub_tag.len();
> +
> + if sub_tag_len == 1 {
You may want to write this as:
match sub_tag.len() {
// Singleton tag...
1 => break,
// ISO 3166-1...
2 => ...,
// ISO 15924...
4 => ...,
_ => continue,
}
if possible, which is slightly more concise.
Attachment #8920442 -
Flags: review?(nfroyd) → review+
Assignee | ||
Comment 15•7 years ago
|
||
Thanks for the quick review! This should be ready for try-server and checkin :)
Attachment #8920625 -
Flags: checkin?(nfroyd)
Updated•7 years ago
|
Assignee: nobody → jthemphill
Comment 16•7 years ago
|
||
Comment on attachment 8920625 [details] [diff] [review]
ship-it.hgpatch
checkin? is usually used for when a patch is ready to land (and better yet, the checkin-needed bug keyword). Moving that over to a needinfo request so this bug doesn't show up on the "patches that are ready to land" bug queries :)
Flags: needinfo?(nfroyd)
Attachment #8920625 -
Flags: checkin?(nfroyd)
Updated•7 years ago
|
Attachment #8920442 -
Attachment is obsolete: true
Comment 17•7 years ago
|
||
Running this on try produced much unhappiness:
https://treeherder.mozilla.org/#/jobs?repo=try&revision=e8e132d34ec983370397da247426eec40fbb39bc
Reading through the patch again, I see that toolkit/library/gtest/rust/Cargo.lock didn't get updated, which is probably the source of the problems. Jeff, can you update that bit, and we can try again?
Flags: needinfo?(nfroyd) → needinfo?(jthemphill)
Assignee | ||
Comment 18•7 years ago
|
||
Updated toolkit/library/gtest/rust/Cargo.lock as well. Grepped for "rust_url_capi" and couldn't find any other lockfiles.
Attachment #8920625 -
Attachment is obsolete: true
Flags: needinfo?(jthemphill) → needinfo?(nfroyd)
Comment 19•7 years ago
|
||
I was just about to check this in, but I realized I hadn't seen a formal r+ from Valentin, just a feedback+. I wanted to make sure the changes suggested in comment 9 had been made, or if there are other things that need to be fixed.
Flags: needinfo?(nfroyd) → needinfo?(valentin.gosu)
Comment 20•7 years ago
|
||
Comment on attachment 8920744 [details] [diff] [review]
updated-gtest-dependency.hgpatch
Review of attachment 8920744 [details] [diff] [review]:
-----------------------------------------------------------------
Only one minor nit that wasn't fixed. Not that important, we could even fix later. r+
::: netwerk/protocol/http/nsHttpHandler.cpp
@@ +1929,4 @@
> if (!i_AcceptLanguages)
> return NS_OK;
>
> + const nsAutoCString ns_accept_languages(i_AcceptLanguages);
nit: by the c++ style naming convention this variable would be called acceptLanguages;
Attachment #8920744 -
Flags: review+
Updated•7 years ago
|
Flags: needinfo?(valentin.gosu)
Comment 21•7 years ago
|
||
Pushed by nfroyd@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/c4c253a9a462
Port nsHttpHandler::PrepareAcceptLanguages over to Rust; r=valentin,froydnj
Comment 22•7 years ago
|
||
bugherder |
Status: NEW → RESOLVED
Closed: 7 years ago
status-firefox58:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla58
You need to log in
before you can comment on or make changes to this bug.
Description
•