Browse Source

url: add ToObject method to native URL class

Provides a factory method to convert a native URL class
into a JS URL object.

```c++
Environment* env = ...

URL url("http://example.org/a/b/c?query#fragment");

MaybeLocal<Value> val = url.ToObject(env);
```

PR-URL: https://github.com/nodejs/node/pull/12056
Reviewed-By: Anna Henningsen <anna@addaleax.net>
v6
James M Snell 8 years ago
parent
commit
7139b93a8b
  1. 4
      lib/internal/bootstrap_node.js
  2. 25
      lib/internal/url.js
  3. 1
      src/env.h
  4. 96
      src/node_url.cc
  5. 9
      src/node_url.h

4
lib/internal/bootstrap_node.js

@ -54,6 +54,10 @@
_process.setupRawDebug();
// Ensure setURLConstructor() is called before the native
// URL::ToObject() method is used.
NativeModule.require('internal/url');
Object.defineProperty(process, 'argv0', {
enumerable: true,
configurable: false,

25
lib/internal/url.js

@ -1400,6 +1400,31 @@ function getPathFromURL(path) {
return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);
}
function NativeURL(ctx) {
this[context] = ctx;
}
NativeURL.prototype = URL.prototype;
function constructUrl(flags, protocol, username, password,
host, port, path, query, fragment) {
var ctx = new URLContext();
ctx.flags = flags;
ctx.scheme = protocol;
ctx.username = username;
ctx.password = password;
ctx.port = port;
ctx.path = path;
ctx.query = query;
ctx.fragment = fragment;
ctx.host = host;
const url = new NativeURL(ctx);
url[searchParams] = new URLSearchParams();
url[searchParams][context] = url;
initSearchParams(url[searchParams], query);
return url;
}
binding.setURLConstructor(constructUrl);
module.exports = {
toUSVString,
getPathFromURL,

1
src/env.h

@ -273,6 +273,7 @@ namespace node {
V(tls_wrap_constructor_template, v8::FunctionTemplate) \
V(tty_constructor_template, v8::FunctionTemplate) \
V(udp_constructor_function, v8::Function) \
V(url_constructor_function, v8::Function) \
V(write_wrap_constructor_function, v8::Function) \
class Environment;

96
src/node_url.cc

@ -27,9 +27,11 @@ using v8::HandleScope;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::Null;
using v8::Object;
using v8::String;
using v8::TryCatch;
using v8::Undefined;
using v8::Value;
@ -1226,6 +1228,29 @@ namespace url {
}
}
static inline void SetArgs(Environment* env,
Local<Value> argv[],
const struct url_data* url) {
Isolate* isolate = env->isolate();
argv[ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url->flags);
if (url->flags & URL_FLAGS_HAS_SCHEME)
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);
}
static void Parse(Environment* env,
Local<Value> recv,
const char* input,
@ -1267,23 +1292,7 @@ namespace url {
undef,
undef,
};
argv[ARG_FLAGS] = Integer::NewFromUnsigned(isolate, url.flags);
if (url.flags & URL_FLAGS_HAS_SCHEME)
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);
SetArgs(env, argv, &url);
(void)cb->Call(context, recv, arraysize(argv), argv);
} else if (error_cb->IsFunction()) {
Local<Value> argv[2] = { undef, undef };
@ -1418,6 +1427,58 @@ namespace url {
v8::NewStringType::kNormal).ToLocalChecked());
}
// This function works by calling out to a JS function that creates and
// returns the JS URL object. Be mindful of the JS<->Native boundary
// crossing that is required.
const Local<Value> URL::ToObject(Environment* env) const {
Isolate* isolate = env->isolate();
Local<Context> context = env->context();
HandleScope handle_scope(isolate);
Context::Scope context_scope(context);
const Local<Value> undef = Undefined(isolate);
if (context_.flags & URL_FLAGS_FAILED)
return Local<Value>();
Local<Value> argv[9] = {
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
undef,
};
SetArgs(env, argv, &context_);
TryCatch try_catch(isolate);
// The SetURLConstructor method must have been called already to
// set the constructor function used below. SetURLConstructor is
// called automatically when the internal/url.js module is loaded
// during the internal/bootstrap_node.js processing.
MaybeLocal<Value> ret =
env->url_constructor_function()
->Call(env->context(), undef, 9, argv);
if (ret.IsEmpty()) {
ClearFatalExceptionHandlers(env);
FatalException(isolate, try_catch);
}
return ret.ToLocalChecked();
}
static void SetURLConstructor(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsFunction());
env->set_url_constructor_function(args[0].As<Function>());
}
static void Init(Local<Object> target,
Local<Value> unused,
Local<Context> context,
@ -1428,6 +1489,7 @@ namespace url {
env->SetMethod(target, "toUSVString", ToUSVString);
env->SetMethod(target, "domainToASCII", DomainToASCII);
env->SetMethod(target, "domainToUnicode", DomainToUnicode);
env->SetMethod(target, "setURLConstructor", SetURLConstructor);
#define XX(name, _) NODE_DEFINE_CONSTANT(target, name);
FLAGS(XX)

9
src/node_url.h

@ -4,11 +4,18 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include "node.h"
#include "env.h"
#include "env-inl.h"
#include <string>
namespace node {
namespace url {
using v8::Local;
using v8::Value;
#define BIT_AT(a, i) \
(!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
(1 << ((unsigned int) (i) & 7))))
@ -619,6 +626,8 @@ class URL {
return ret;
}
const Local<Value> ToObject(Environment* env) const;
private:
struct url_data context_;
};

Loading…
Cancel
Save