src: general C++ cleanup in node_url.cc
- Merge `domain` and `opaque` storage in URL parser: This just simplifies the code a bit, having multiple fields in an union with the same type is usually just overhead. - Add move variant of `URLHost::ToString()`: This helps avoid unnecessary string copy operations, especially since we control the lifetime of `URLHost` objects pretty well. - Use const refs in node_url.cc where appropriate - Remove or reduce overly generous `.reserve()` calls: These would otherwise keep a lot of unused memory lying around. - Return return values instead of unnecessary pointer arguments - Use more common/expressive variable names - Avoid macro use, reduce number of unnecessary JS strings: There’s no reason for `GET`, `GET_AND_SET` and `UTF8STRING` to be macros. Also, `GET` would previously create a JS string instance for each single call, even though the strings it was called with were compile-time constants. - Avoid unnecessary JS casts when the type of a value is known - Avoid (commonly unnecessary) copy for whitespace stripping PR-URL: https://github.com/nodejs/node/pull/19598 Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
This commit is contained in:
parent
b7cfd278a5
commit
ae70e2bc34
@ -165,11 +165,13 @@ struct PackageConfig {
|
||||
V(fingerprint_string, "fingerprint") \
|
||||
V(fingerprint256_string, "fingerprint256") \
|
||||
V(flags_string, "flags") \
|
||||
V(fragment_string, "fragment") \
|
||||
V(get_data_clone_error_string, "_getDataCloneError") \
|
||||
V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \
|
||||
V(gid_string, "gid") \
|
||||
V(handle_string, "handle") \
|
||||
V(homedir_string, "homedir") \
|
||||
V(host_string, "host") \
|
||||
V(hostmaster_string, "hostmaster") \
|
||||
V(ignore_string, "ignore") \
|
||||
V(infoaccess_string, "infoAccess") \
|
||||
@ -226,6 +228,7 @@ struct PackageConfig {
|
||||
V(order_string, "order") \
|
||||
V(owner_string, "owner") \
|
||||
V(parse_error_string, "Parse Error") \
|
||||
V(password_string, "password") \
|
||||
V(path_string, "path") \
|
||||
V(pending_handle_string, "pendingHandle") \
|
||||
V(pbkdf2_error_string, "PBKDF2 Error") \
|
||||
@ -239,6 +242,7 @@ struct PackageConfig {
|
||||
V(produce_cached_data_string, "produceCachedData") \
|
||||
V(promise_string, "promise") \
|
||||
V(pubkey_string, "pubkey") \
|
||||
V(query_string, "query") \
|
||||
V(raw_string, "raw") \
|
||||
V(read_host_object_string, "_readHostObject") \
|
||||
V(readable_string, "readable") \
|
||||
@ -247,6 +251,7 @@ struct PackageConfig {
|
||||
V(rename_string, "rename") \
|
||||
V(replacement_string, "replacement") \
|
||||
V(retry_string, "retry") \
|
||||
V(scheme_string, "scheme") \
|
||||
V(serial_string, "serial") \
|
||||
V(scopeid_string, "scopeid") \
|
||||
V(serial_number_string, "serialNumber") \
|
||||
|
334
src/node_url.cc
334
src/node_url.cc
@ -15,6 +15,7 @@ using v8::Context;
|
||||
using v8::Function;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::HandleScope;
|
||||
using v8::Int32;
|
||||
using v8::Integer;
|
||||
using v8::Isolate;
|
||||
using v8::Local;
|
||||
@ -26,23 +27,12 @@ using v8::TryCatch;
|
||||
using v8::Undefined;
|
||||
using v8::Value;
|
||||
|
||||
#define GET(env, obj, name) \
|
||||
obj->Get(env->context(), \
|
||||
OneByteString(env->isolate(), name)).ToLocalChecked()
|
||||
|
||||
#define GET_AND_SET(env, obj, name, data, flag) \
|
||||
{ \
|
||||
Local<Value> val = GET(env, obj, #name); \
|
||||
if (val->IsString()) { \
|
||||
Utf8Value value(env->isolate(), val.As<String>()); \
|
||||
data->name = *value; \
|
||||
data->flags |= flag; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define UTF8STRING(isolate, str) \
|
||||
String::NewFromUtf8(isolate, str.c_str(), v8::NewStringType::kNormal) \
|
||||
.ToLocalChecked()
|
||||
inline Local<String> Utf8String(Isolate* isolate, const std::string& str) {
|
||||
return String::NewFromUtf8(isolate,
|
||||
str.data(),
|
||||
v8::NewStringType::kNormal,
|
||||
str.length()).ToLocalChecked();
|
||||
}
|
||||
|
||||
namespace url {
|
||||
|
||||
@ -69,6 +59,8 @@ class URLHost {
|
||||
|
||||
inline bool ParsingFailed() const { return type_ == HostType::H_FAILED; }
|
||||
std::string ToString() const;
|
||||
// Like ToString(), but avoids a copy in exchange for invalidating `*this`.
|
||||
std::string ToStringMove();
|
||||
|
||||
private:
|
||||
enum class HostType {
|
||||
@ -80,10 +72,9 @@ class URLHost {
|
||||
};
|
||||
|
||||
union Value {
|
||||
std::string domain;
|
||||
std::string domain_or_opaque;
|
||||
uint32_t ipv4;
|
||||
uint16_t ipv6[8];
|
||||
std::string opaque;
|
||||
|
||||
~Value() {}
|
||||
Value() : ipv4(0) {}
|
||||
@ -95,9 +86,12 @@ class URLHost {
|
||||
inline void Reset() {
|
||||
using string = std::string;
|
||||
switch (type_) {
|
||||
case HostType::H_DOMAIN: value_.domain.~string(); break;
|
||||
case HostType::H_OPAQUE: value_.opaque.~string(); break;
|
||||
default: break;
|
||||
case HostType::H_DOMAIN:
|
||||
case HostType::H_OPAQUE:
|
||||
value_.domain_or_opaque.~string();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
type_ = HostType::H_FAILED;
|
||||
}
|
||||
@ -113,13 +107,13 @@ class URLHost {
|
||||
inline void SetOpaque(std::string&& string) {
|
||||
Reset();
|
||||
type_ = HostType::H_OPAQUE;
|
||||
new(&value_.opaque) std::string(std::move(string));
|
||||
new(&value_.domain_or_opaque) std::string(std::move(string));
|
||||
}
|
||||
|
||||
inline void SetDomain(std::string&& string) {
|
||||
Reset();
|
||||
type_ = HostType::H_DOMAIN;
|
||||
new(&value_.domain) std::string(std::move(string));
|
||||
new(&value_.domain_or_opaque) std::string(std::move(string));
|
||||
}
|
||||
};
|
||||
|
||||
@ -136,7 +130,8 @@ URLHost::~URLHost() {
|
||||
XX(ARG_PORT) \
|
||||
XX(ARG_PATH) \
|
||||
XX(ARG_QUERY) \
|
||||
XX(ARG_FRAGMENT)
|
||||
XX(ARG_FRAGMENT) \
|
||||
XX(ARG_COUNT) // This one has to be last.
|
||||
|
||||
#define ERR_ARGS(XX) \
|
||||
XX(ERR_ARG_FLAGS) \
|
||||
@ -665,7 +660,7 @@ inline std::string PercentDecode(const char* input, size_t len) {
|
||||
XX("ws:", 80) \
|
||||
XX("wss:", 443)
|
||||
|
||||
inline bool IsSpecial(std::string scheme) {
|
||||
inline bool IsSpecial(const std::string& scheme) {
|
||||
#define XX(name, _) if (scheme == name) return true;
|
||||
SPECIALS(XX);
|
||||
#undef XX
|
||||
@ -684,7 +679,7 @@ inline bool StartsWithWindowsDriveLetter(const char* p, const char* end) {
|
||||
p[2] == '#');
|
||||
}
|
||||
|
||||
inline int NormalizePort(std::string scheme, int p) {
|
||||
inline int NormalizePort(const std::string& scheme, int p) {
|
||||
#define XX(name, port) if (scheme == name && p == port) return -1;
|
||||
SPECIALS(XX);
|
||||
#undef XX
|
||||
@ -930,7 +925,7 @@ void URLHost::ParseIPv4Host(const char* input, size_t length, bool* is_ipv4) {
|
||||
void URLHost::ParseOpaqueHost(const char* input, size_t length) {
|
||||
CHECK_EQ(type_, HostType::H_FAILED);
|
||||
std::string output;
|
||||
output.reserve(length * 3);
|
||||
output.reserve(length);
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
const char ch = input[i];
|
||||
if (ch != '%' && IsForbiddenHostCodePoint(ch)) {
|
||||
@ -1022,14 +1017,27 @@ inline T* FindLongestZeroSequence(T* values, size_t len) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string URLHost::ToStringMove() {
|
||||
std::string return_value;
|
||||
switch (type_) {
|
||||
case HostType::H_DOMAIN:
|
||||
case HostType::H_OPAQUE:
|
||||
return_value = std::move(value_.domain_or_opaque);
|
||||
break;
|
||||
default:
|
||||
return_value = ToString();
|
||||
break;
|
||||
}
|
||||
Reset();
|
||||
return return_value;
|
||||
}
|
||||
|
||||
std::string URLHost::ToString() const {
|
||||
std::string dest;
|
||||
switch (type_) {
|
||||
case HostType::H_DOMAIN:
|
||||
return value_.domain;
|
||||
break;
|
||||
case HostType::H_OPAQUE:
|
||||
return value_.opaque;
|
||||
return value_.domain_or_opaque;
|
||||
break;
|
||||
case HostType::H_IPV4: {
|
||||
dest.reserve(15);
|
||||
@ -1089,103 +1097,125 @@ bool ParseHost(const std::string& input,
|
||||
host.ParseHost(input.c_str(), input.length(), is_special, unicode);
|
||||
if (host.ParsingFailed())
|
||||
return false;
|
||||
*output = host.ToString();
|
||||
*output = host.ToStringMove();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void Copy(Environment* env,
|
||||
Local<Array> ary,
|
||||
std::vector<std::string>* vec) {
|
||||
const int32_t len = ary->Length();
|
||||
inline std::vector<std::string> FromJSStringArray(Environment* env,
|
||||
Local<Array> array) {
|
||||
std::vector<std::string> vec;
|
||||
const int32_t len = array->Length();
|
||||
if (len == 0)
|
||||
return; // nothing to copy
|
||||
vec->reserve(len);
|
||||
return vec; // nothing to copy
|
||||
vec.reserve(len);
|
||||
for (int32_t n = 0; n < len; n++) {
|
||||
Local<Value> val = ary->Get(env->context(), n).ToLocalChecked();
|
||||
Local<Value> val = array->Get(env->context(), n).ToLocalChecked();
|
||||
if (val->IsString()) {
|
||||
Utf8Value value(env->isolate(), val.As<String>());
|
||||
vec->push_back(std::string(*value, value.length()));
|
||||
vec.emplace_back(*value, value.length());
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
inline Local<Array> Copy(Environment* env,
|
||||
const std::vector<std::string>& vec) {
|
||||
inline Local<Array> ToJSStringArray(Environment* env,
|
||||
const std::vector<std::string>& vec) {
|
||||
Isolate* isolate = env->isolate();
|
||||
Local<Array> ary = Array::New(isolate, vec.size());
|
||||
Local<Array> array = Array::New(isolate, vec.size());
|
||||
for (size_t n = 0; n < vec.size(); n++)
|
||||
ary->Set(env->context(), n, UTF8STRING(isolate, vec[n])).FromJust();
|
||||
return ary;
|
||||
array->Set(env->context(), n, Utf8String(isolate, vec[n])).FromJust();
|
||||
return array;
|
||||
}
|
||||
|
||||
inline void HarvestBase(Environment* env,
|
||||
struct url_data* base,
|
||||
Local<Object> base_obj) {
|
||||
inline url_data HarvestBase(Environment* env, Local<Object> base_obj) {
|
||||
url_data base;
|
||||
Local<Context> context = env->context();
|
||||
Local<Value> flags = GET(env, base_obj, "flags");
|
||||
Local<Value> flags =
|
||||
base_obj->Get(env->context(), env->flags_string()).ToLocalChecked();
|
||||
if (flags->IsInt32())
|
||||
base->flags = flags->Int32Value(context).FromJust();
|
||||
base.flags = flags->Int32Value(context).FromJust();
|
||||
|
||||
Local<Value> scheme = GET(env, base_obj, "scheme");
|
||||
base->scheme = Utf8Value(env->isolate(), scheme).out();
|
||||
Local<Value> scheme =
|
||||
base_obj->Get(env->context(), env->scheme_string()).ToLocalChecked();
|
||||
base.scheme = Utf8Value(env->isolate(), scheme).out();
|
||||
|
||||
GET_AND_SET(env, base_obj, username, base, URL_FLAGS_HAS_USERNAME);
|
||||
GET_AND_SET(env, base_obj, password, base, URL_FLAGS_HAS_PASSWORD);
|
||||
GET_AND_SET(env, base_obj, host, base, URL_FLAGS_HAS_HOST);
|
||||
GET_AND_SET(env, base_obj, query, base, URL_FLAGS_HAS_QUERY);
|
||||
GET_AND_SET(env, base_obj, fragment, base, URL_FLAGS_HAS_FRAGMENT);
|
||||
Local<Value> port = GET(env, base_obj, "port");
|
||||
auto GetStr = [&](std::string url_data::* member,
|
||||
int flag,
|
||||
Local<String> name) {
|
||||
Local<Value> value = base_obj->Get(env->context(), name).ToLocalChecked();
|
||||
if (value->IsString()) {
|
||||
Utf8Value utf8value(env->isolate(), value.As<String>());
|
||||
(base.*member).assign(*utf8value, utf8value.length());
|
||||
base.flags |= flag;
|
||||
}
|
||||
};
|
||||
GetStr(&url_data::username, URL_FLAGS_HAS_USERNAME, env->username_string());
|
||||
GetStr(&url_data::password, URL_FLAGS_HAS_PASSWORD, env->password_string());
|
||||
GetStr(&url_data::host, URL_FLAGS_HAS_HOST, env->host_string());
|
||||
GetStr(&url_data::query, URL_FLAGS_HAS_QUERY, env->query_string());
|
||||
GetStr(&url_data::fragment, URL_FLAGS_HAS_FRAGMENT, env->fragment_string());
|
||||
|
||||
Local<Value> port =
|
||||
base_obj->Get(env->context(), env->port_string()).ToLocalChecked();
|
||||
if (port->IsInt32())
|
||||
base->port = port->Int32Value(context).FromJust();
|
||||
Local<Value> path = GET(env, base_obj, "path");
|
||||
base.port = port.As<Int32>()->Value();
|
||||
|
||||
Local<Value>
|
||||
path = base_obj->Get(env->context(), env->path_string()).ToLocalChecked();
|
||||
if (path->IsArray()) {
|
||||
base->flags |= URL_FLAGS_HAS_PATH;
|
||||
Copy(env, path.As<Array>(), &(base->path));
|
||||
base.flags |= URL_FLAGS_HAS_PATH;
|
||||
base.path = FromJSStringArray(env, path.As<Array>());
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
inline void HarvestContext(Environment* env,
|
||||
struct url_data* context,
|
||||
Local<Object> context_obj) {
|
||||
Local<Value> flags = GET(env, context_obj, "flags");
|
||||
inline url_data HarvestContext(Environment* env, Local<Object> context_obj) {
|
||||
url_data context;
|
||||
Local<Value> flags =
|
||||
context_obj->Get(env->context(), env->flags_string()).ToLocalChecked();
|
||||
if (flags->IsInt32()) {
|
||||
int32_t _flags = flags->Int32Value(env->context()).FromJust();
|
||||
if (_flags & URL_FLAGS_SPECIAL)
|
||||
context->flags |= URL_FLAGS_SPECIAL;
|
||||
if (_flags & URL_FLAGS_CANNOT_BE_BASE)
|
||||
context->flags |= URL_FLAGS_CANNOT_BE_BASE;
|
||||
if (_flags & URL_FLAGS_HAS_USERNAME)
|
||||
context->flags |= URL_FLAGS_HAS_USERNAME;
|
||||
if (_flags & URL_FLAGS_HAS_PASSWORD)
|
||||
context->flags |= URL_FLAGS_HAS_PASSWORD;
|
||||
if (_flags & URL_FLAGS_HAS_HOST)
|
||||
context->flags |= URL_FLAGS_HAS_HOST;
|
||||
static const int32_t copy_flags_mask =
|
||||
URL_FLAGS_SPECIAL |
|
||||
URL_FLAGS_CANNOT_BE_BASE |
|
||||
URL_FLAGS_HAS_USERNAME |
|
||||
URL_FLAGS_HAS_PASSWORD |
|
||||
URL_FLAGS_HAS_HOST;
|
||||
context.flags |= flags.As<Int32>()->Value() & copy_flags_mask;
|
||||
}
|
||||
Local<Value> scheme = GET(env, context_obj, "scheme");
|
||||
Local<Value> scheme =
|
||||
context_obj->Get(env->context(), env->scheme_string()).ToLocalChecked();
|
||||
if (scheme->IsString()) {
|
||||
Utf8Value value(env->isolate(), scheme);
|
||||
context->scheme.assign(*value, value.length());
|
||||
context.scheme.assign(*value, value.length());
|
||||
}
|
||||
Local<Value> port = GET(env, context_obj, "port");
|
||||
Local<Value> port =
|
||||
context_obj->Get(env->context(), env->port_string()).ToLocalChecked();
|
||||
if (port->IsInt32())
|
||||
context->port = port->Int32Value(env->context()).FromJust();
|
||||
if (context->flags & URL_FLAGS_HAS_USERNAME) {
|
||||
Local<Value> username = GET(env, context_obj, "username");
|
||||
context.port = port.As<Int32>()->Value();
|
||||
if (context.flags & URL_FLAGS_HAS_USERNAME) {
|
||||
Local<Value> username =
|
||||
context_obj->Get(env->context(),
|
||||
env->username_string()).ToLocalChecked();
|
||||
CHECK(username->IsString());
|
||||
Utf8Value value(env->isolate(), username);
|
||||
context->username.assign(*value, value.length());
|
||||
context.username.assign(*value, value.length());
|
||||
}
|
||||
if (context->flags & URL_FLAGS_HAS_PASSWORD) {
|
||||
Local<Value> password = GET(env, context_obj, "password");
|
||||
if (context.flags & URL_FLAGS_HAS_PASSWORD) {
|
||||
Local<Value> password =
|
||||
context_obj->Get(env->context(),
|
||||
env->password_string()).ToLocalChecked();
|
||||
CHECK(password->IsString());
|
||||
Utf8Value value(env->isolate(), password);
|
||||
context->password.assign(*value, value.length());
|
||||
context.password.assign(*value, value.length());
|
||||
}
|
||||
Local<Value> host = GET(env, context_obj, "host");
|
||||
Local<Value> host =
|
||||
context_obj->Get(env->context(),
|
||||
env->host_string()).ToLocalChecked();
|
||||
if (host->IsString()) {
|
||||
Utf8Value value(env->isolate(), host);
|
||||
context->host.assign(*value, value.length());
|
||||
context.host.assign(*value, value.length());
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
// Single dot segment can be ".", "%2e", or "%2E"
|
||||
@ -1267,30 +1297,37 @@ void URL::Parse(const char* input,
|
||||
len = end - p;
|
||||
}
|
||||
|
||||
// The spec says we should strip out any ASCII tabs or newlines.
|
||||
// In those cases, we create another std::string instance with the filtered
|
||||
// contents, but in the general case we avoid the overhead.
|
||||
std::string whitespace_stripped;
|
||||
whitespace_stripped.reserve(len);
|
||||
for (const char* ptr = p; ptr < end; ptr++)
|
||||
for (const char* ptr = p; ptr < end; ptr++) {
|
||||
if (!IsASCIITabOrNewline(*ptr))
|
||||
whitespace_stripped += *ptr;
|
||||
continue;
|
||||
// Hit tab or newline. Allocate storage, copy what we have until now,
|
||||
// and then iterate and filter all similar characters out.
|
||||
whitespace_stripped.reserve(len - 1);
|
||||
whitespace_stripped.assign(p, ptr - p);
|
||||
// 'ptr + 1' skips the current char, which we know to be tab or newline.
|
||||
for (ptr = ptr + 1; ptr < end; ptr++) {
|
||||
if (!IsASCIITabOrNewline(*ptr))
|
||||
whitespace_stripped += *ptr;
|
||||
}
|
||||
|
||||
input = whitespace_stripped.c_str();
|
||||
len = whitespace_stripped.size();
|
||||
p = input;
|
||||
end = input + len;
|
||||
// Update variables like they should have looked like if the string
|
||||
// had been stripped of whitespace to begin with.
|
||||
input = whitespace_stripped.c_str();
|
||||
len = whitespace_stripped.size();
|
||||
p = input;
|
||||
end = input + len;
|
||||
break;
|
||||
}
|
||||
|
||||
bool atflag = false;
|
||||
bool sbflag = false;
|
||||
bool uflag = false;
|
||||
bool atflag = false; // Set when @ has been seen.
|
||||
bool square_bracket_flag = false; // Set inside of [...]
|
||||
bool password_token_seen_flag = false; // Set after a : after an username.
|
||||
|
||||
std::string buffer;
|
||||
url->scheme.reserve(len);
|
||||
url->username.reserve(len);
|
||||
url->password.reserve(len);
|
||||
url->host.reserve(len);
|
||||
url->path.reserve(len);
|
||||
url->query.reserve(len);
|
||||
url->fragment.reserve(len);
|
||||
buffer.reserve(len);
|
||||
|
||||
// Set the initial parse state.
|
||||
const bool has_state_override = state_override != kUnknownState;
|
||||
@ -1347,7 +1384,7 @@ void URL::Parse(const char* input,
|
||||
// as it can be done before even entering C++ binding.
|
||||
}
|
||||
|
||||
url->scheme = buffer;
|
||||
url->scheme = std::move(buffer);
|
||||
url->port = NormalizePort(url->scheme, url->port);
|
||||
if (new_is_special) {
|
||||
url->flags |= URL_FLAGS_SPECIAL;
|
||||
@ -1373,7 +1410,7 @@ void URL::Parse(const char* input,
|
||||
} else {
|
||||
url->flags |= URL_FLAGS_CANNOT_BE_BASE;
|
||||
url->flags |= URL_FLAGS_HAS_PATH;
|
||||
url->path.push_back("");
|
||||
url->path.emplace_back("");
|
||||
state = kCannotBeBase;
|
||||
}
|
||||
} else if (!has_state_override) {
|
||||
@ -1602,12 +1639,12 @@ void URL::Parse(const char* input,
|
||||
const char bch = buffer[n];
|
||||
if (bch == ':') {
|
||||
url->flags |= URL_FLAGS_HAS_PASSWORD;
|
||||
if (!uflag) {
|
||||
uflag = true;
|
||||
if (!password_token_seen_flag) {
|
||||
password_token_seen_flag = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (uflag) {
|
||||
if (password_token_seen_flag) {
|
||||
AppendOrEscape(&url->password, bch, USERINFO_ENCODE_SET);
|
||||
} else {
|
||||
AppendOrEscape(&url->username, bch, USERINFO_ENCODE_SET);
|
||||
@ -1635,7 +1672,7 @@ void URL::Parse(const char* input,
|
||||
if (has_state_override && url->scheme == "file:") {
|
||||
state = kFileHost;
|
||||
continue;
|
||||
} else if (ch == ':' && !sbflag) {
|
||||
} else if (ch == ':' && !square_bracket_flag) {
|
||||
if (buffer.size() == 0) {
|
||||
url->flags |= URL_FLAGS_FAILED;
|
||||
return;
|
||||
@ -1679,9 +1716,9 @@ void URL::Parse(const char* input,
|
||||
}
|
||||
} else {
|
||||
if (ch == '[')
|
||||
sbflag = true;
|
||||
square_bracket_flag = true;
|
||||
if (ch == ']')
|
||||
sbflag = false;
|
||||
square_bracket_flag = false;
|
||||
buffer += ch;
|
||||
}
|
||||
break;
|
||||
@ -1888,12 +1925,12 @@ void URL::Parse(const char* input,
|
||||
ShortenUrlPath(url);
|
||||
if (ch != '/' && !special_back_slash) {
|
||||
url->flags |= URL_FLAGS_HAS_PATH;
|
||||
url->path.push_back("");
|
||||
url->path.emplace_back("");
|
||||
}
|
||||
} else if (IsSingleDotSegment(buffer) &&
|
||||
ch != '/' && !special_back_slash) {
|
||||
url->flags |= URL_FLAGS_HAS_PATH;
|
||||
url->path.push_back("");
|
||||
url->path.emplace_back("");
|
||||
} else if (!IsSingleDotSegment(buffer)) {
|
||||
if (url->scheme == "file:" &&
|
||||
url->path.empty() &&
|
||||
@ -1907,8 +1944,7 @@ void URL::Parse(const char* input,
|
||||
buffer[1] = ':';
|
||||
}
|
||||
url->flags |= URL_FLAGS_HAS_PATH;
|
||||
std::string segment(buffer.c_str(), buffer.size());
|
||||
url->path.push_back(segment);
|
||||
url->path.emplace_back(std::move(buffer));
|
||||
}
|
||||
buffer.clear();
|
||||
if (url->scheme == "file:" &&
|
||||
@ -1947,7 +1983,7 @@ void URL::Parse(const char* input,
|
||||
case kQuery:
|
||||
if (ch == kEOL || (!has_state_override && ch == '#')) {
|
||||
url->flags |= URL_FLAGS_HAS_QUERY;
|
||||
url->query = buffer;
|
||||
url->query = std::move(buffer);
|
||||
buffer.clear();
|
||||
if (ch == '#')
|
||||
state = kFragment;
|
||||
@ -1959,7 +1995,7 @@ void URL::Parse(const char* input,
|
||||
switch (ch) {
|
||||
case kEOL:
|
||||
url->flags |= URL_FLAGS_HAS_FRAGMENT;
|
||||
url->fragment = buffer;
|
||||
url->fragment = std::move(buffer);
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
@ -1977,25 +2013,25 @@ void URL::Parse(const char* input,
|
||||
} // NOLINT(readability/fn_size)
|
||||
|
||||
static inline void SetArgs(Environment* env,
|
||||
Local<Value> argv[],
|
||||
const struct url_data* url) {
|
||||
Local<Value> argv[ARG_COUNT],
|
||||
const struct url_data& url) {
|
||||
Isolate* isolate = env->isolate();
|
||||
argv[ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url->flags);
|
||||
argv[ARG_PROTOCOL] = OneByteString(isolate, url->scheme.c_str());
|
||||
if (url->flags & URL_FLAGS_HAS_USERNAME)
|
||||
argv[ARG_USERNAME] = UTF8STRING(isolate, url->username);
|
||||
if (url->flags & URL_FLAGS_HAS_PASSWORD)
|
||||
argv[ARG_PASSWORD] = UTF8STRING(isolate, url->password);
|
||||
if (url->flags & URL_FLAGS_HAS_HOST)
|
||||
argv[ARG_HOST] = UTF8STRING(isolate, url->host);
|
||||
if (url->flags & URL_FLAGS_HAS_QUERY)
|
||||
argv[ARG_QUERY] = UTF8STRING(isolate, url->query);
|
||||
if (url->flags & URL_FLAGS_HAS_FRAGMENT)
|
||||
argv[ARG_FRAGMENT] = UTF8STRING(isolate, url->fragment);
|
||||
if (url->port > -1)
|
||||
argv[ARG_PORT] = Integer::New(isolate, url->port);
|
||||
if (url->flags & URL_FLAGS_HAS_PATH)
|
||||
argv[ARG_PATH] = Copy(env, url->path);
|
||||
argv[ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url.flags);
|
||||
argv[ARG_PROTOCOL] = OneByteString(isolate, url.scheme.c_str());
|
||||
if (url.flags & URL_FLAGS_HAS_USERNAME)
|
||||
argv[ARG_USERNAME] = Utf8String(isolate, url.username);
|
||||
if (url.flags & URL_FLAGS_HAS_PASSWORD)
|
||||
argv[ARG_PASSWORD] = Utf8String(isolate, url.password);
|
||||
if (url.flags & URL_FLAGS_HAS_HOST)
|
||||
argv[ARG_HOST] = Utf8String(isolate, url.host);
|
||||
if (url.flags & URL_FLAGS_HAS_QUERY)
|
||||
argv[ARG_QUERY] = Utf8String(isolate, url.query);
|
||||
if (url.flags & URL_FLAGS_HAS_FRAGMENT)
|
||||
argv[ARG_FRAGMENT] = Utf8String(isolate, url.fragment);
|
||||
if (url.port > -1)
|
||||
argv[ARG_PORT] = Integer::New(isolate, url.port);
|
||||
if (url.flags & URL_FLAGS_HAS_PATH)
|
||||
argv[ARG_PATH] = ToJSStringArray(env, url.path);
|
||||
}
|
||||
|
||||
static void Parse(Environment* env,
|
||||
@ -2015,12 +2051,12 @@ static void Parse(Environment* env,
|
||||
const bool has_context = context_obj->IsObject();
|
||||
const bool has_base = base_obj->IsObject();
|
||||
|
||||
struct url_data base;
|
||||
struct url_data url;
|
||||
url_data base;
|
||||
url_data url;
|
||||
if (has_context)
|
||||
HarvestContext(env, &url, context_obj.As<Object>());
|
||||
url = HarvestContext(env, context_obj.As<Object>());
|
||||
if (has_base)
|
||||
HarvestBase(env, &base, base_obj.As<Object>());
|
||||
base = HarvestBase(env, base_obj.As<Object>());
|
||||
|
||||
URL::Parse(input, len, state_override, &url, has_context, &base, has_base);
|
||||
if ((url.flags & URL_FLAGS_INVALID_PARSE_STATE) ||
|
||||
@ -2032,7 +2068,7 @@ static void Parse(Environment* env,
|
||||
const Local<Value> undef = Undefined(isolate);
|
||||
const Local<Value> null = Null(isolate);
|
||||
if (!(url.flags & URL_FLAGS_FAILED)) {
|
||||
Local<Value> argv[9] = {
|
||||
Local<Value> argv[] = {
|
||||
undef,
|
||||
undef,
|
||||
undef,
|
||||
@ -2043,7 +2079,7 @@ static void Parse(Environment* env,
|
||||
null, // query defaults to null
|
||||
null, // fragment defaults to null
|
||||
};
|
||||
SetArgs(env, argv, &url);
|
||||
SetArgs(env, argv, url);
|
||||
cb->Call(context, recv, arraysize(argv), argv).FromMaybe(Local<Value>());
|
||||
} else if (error_cb->IsFunction()) {
|
||||
Local<Value> argv[2] = { undef, undef };
|
||||
@ -2152,7 +2188,7 @@ static void DomainToASCII(const FunctionCallbackInfo<Value>& args) {
|
||||
args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING(env->isolate(), ""));
|
||||
return;
|
||||
}
|
||||
std::string out = host.ToString();
|
||||
std::string out = host.ToStringMove();
|
||||
args.GetReturnValue().Set(
|
||||
String::NewFromUtf8(env->isolate(),
|
||||
out.c_str(),
|
||||
@ -2172,7 +2208,7 @@ static void DomainToUnicode(const FunctionCallbackInfo<Value>& args) {
|
||||
args.GetReturnValue().Set(FIXED_ONE_BYTE_STRING(env->isolate(), ""));
|
||||
return;
|
||||
}
|
||||
std::string out = host.ToString();
|
||||
std::string out = host.ToStringMove();
|
||||
args.GetReturnValue().Set(
|
||||
String::NewFromUtf8(env->isolate(),
|
||||
out.c_str(),
|
||||
@ -2255,7 +2291,7 @@ const Local<Value> URL::ToObject(Environment* env) const {
|
||||
if (context_.flags & URL_FLAGS_FAILED)
|
||||
return Local<Value>();
|
||||
|
||||
Local<Value> argv[9] = {
|
||||
Local<Value> argv[] = {
|
||||
undef,
|
||||
undef,
|
||||
undef,
|
||||
@ -2266,7 +2302,7 @@ const Local<Value> URL::ToObject(Environment* env) const {
|
||||
null, // query defaults to null
|
||||
null, // fragment defaults to null
|
||||
};
|
||||
SetArgs(env, argv, &context_);
|
||||
SetArgs(env, argv, context_);
|
||||
|
||||
MaybeLocal<Value> ret;
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user