Skip to content

Commit

Permalink
feat: allow http-parser NODE_OPTION in packaged apps (#21694) (#22539)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarshallOfSound committed Mar 6, 2020
1 parent 6f88108 commit 33f5fa3
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 50 deletions.
7 changes: 6 additions & 1 deletion docs/api/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ Unsupported options are:
--use-openssl-ca
```

`NODE_OPTIONS` are explicitly disallowed in packaged apps.
`NODE_OPTIONS` are explicitly disallowed in packaged apps, except for the following:

```sh
--max-http-header-size
--http-parser
```

### `GOOGLE_API_KEY`

Expand Down
107 changes: 58 additions & 49 deletions shell/common/node_bindings.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <algorithm>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -122,6 +123,62 @@ void stop_and_close_uv_loop(uv_loop_t* loop) {

bool g_is_initialized = false;

bool IsPackagedApp() {
base::FilePath exe_path;
base::PathService::Get(base::FILE_EXE, &exe_path);
base::FilePath::StringType base_name =
base::ToLowerASCII(exe_path.BaseName().value());

#if defined(OS_WIN)
return base_name != FILE_PATH_LITERAL("electron.exe");
#else
return base_name != FILE_PATH_LITERAL("electron");
#endif
}

// Initialize NODE_OPTIONS to pass to Node.js
void SetNodeOptions(base::Environment* env) {
// Options that are unilaterally disallowed
const std::set<std::string> disallowed = {
"--openssl-config", "--use-bundled-ca", "--use-openssl-ca",
"--force-fips", "--enable-fips"};

// Subset of options allowed in packaged apps
const std::set<std::string> allowed_in_packaged = {"--max-http-header-size",
"--http-parser"};

if (env->HasVar("NODE_OPTIONS")) {
std::string options;
env->GetVar("NODE_OPTIONS", &options);
std::vector<std::string> parts = base::SplitString(
options, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);

bool is_packaged_app = IsPackagedApp();

for (const auto& part : parts) {
// Strip off values passed to individual NODE_OPTIONs
std::string option = part.substr(0, part.find("="));

if (is_packaged_app &&
allowed_in_packaged.find(option) == allowed_in_packaged.end()) {
// Explicitly disallow majority of NODE_OPTIONS in packaged apps
LOG(ERROR) << "Most NODE_OPTIONs are not supported in packaged apps."
<< " See documentation for more details.";
options.erase(options.find(option), part.length());
} else if (disallowed.find(option) != disallowed.end()) {
// Remove NODE_OPTIONS specifically disallowed for use in Node.js
// through Electron owing to constraints like BoringSSL.
LOG(ERROR) << "The NODE_OPTION " << option
<< " is not supported in Electron";
options.erase(options.find(option), part.length());
}
}

// overwrite new NODE_OPTIONS without unsupported variables
env->SetVar("NODE_OPTIONS", options);
}
}

} // namespace

namespace electron {
Expand Down Expand Up @@ -222,55 +279,7 @@ void NodeBindings::Initialize() {
const char** exec_argv = nullptr;

std::unique_ptr<base::Environment> env(base::Environment::Create());
if (env->HasVar("NODE_OPTIONS")) {
base::FilePath exe_path;
base::PathService::Get(base::FILE_EXE, &exe_path);
#if defined(OS_WIN)
std::string path = base::UTF16ToUTF8(exe_path.value());
#else
std::string path = exe_path.value();
#endif
std::transform(path.begin(), path.end(), path.begin(), ::tolower);

#if defined(OS_WIN)
const bool is_packaged_app = path == "electron.exe";
#else
const bool is_packaged_app = path == "electron";
#endif

// explicitly disallow NODE_OPTIONS in packaged apps
if (is_packaged_app) {
LOG(WARNING) << "NODE_OPTIONs are not supported in packaged apps";
env->SetVar("NODE_OPTIONS", "");
} else {
const std::vector<std::string> disallowed = {
"--openssl-config", "--use-bundled-ca", "--use-openssl-ca",
"--force-fips", "--enable-fips"};

std::string options;
env->GetVar("NODE_OPTIONS", &options);
std::vector<std::string> parts = base::SplitString(
options, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);

// parse passed options for unsupported options
// and remove them from the options list
std::string new_options = options;
for (const auto& disallow : disallowed) {
for (const auto& part : parts) {
if (part.find(disallow) != std::string::npos) {
LOG(WARNING) << "The NODE_OPTION" << disallow
<< "is not supported in Electron";
new_options.erase(new_options.find(part), part.length());
break;
}
}
}

// overwrite new NODE_OPTIONS without unsupported variables
if (new_options != options)
env->SetVar("NODE_OPTIONS", new_options);
}
}
SetNodeOptions(env.get());

// TODO(codebytere): this is going to be deprecated in the near future
// in favor of Init(std::vector<std::string>* argv,
Expand Down

0 comments on commit 33f5fa3

Please sign in to comment.