Skip to content
This repository has been archived by the owner on Oct 15, 2020. It is now read-only.

Commit

Permalink
Merge nodejs/master to xplat
Browse files Browse the repository at this point in the history
Merge commit 8250bfd as of 2017-05-20 into xplat
  • Loading branch information
kunalspathak committed May 22, 2017
2 parents b3b3626 + 8250bfd commit 4fc607f
Show file tree
Hide file tree
Showing 38 changed files with 458 additions and 315 deletions.
4 changes: 4 additions & 0 deletions COLLABORATOR_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ you can run [`citgm-abi-smoker`](https://ci.nodejs.org/job/citgm-abi-smoker/).
is designed to allow one to run a group of tests over and over on a specific
platform to confirm that the test is reliable.

* [`node-test-commit-v8-linux`](https://ci.nodejs.org/job/node-test-commit-v8-linux/)
is designed to allow validation of changes to the copy of V8 in the Node.js
tree by running the standard V8 tests. It should be run whenever the
level of V8 within Node.js is updated or new patches are floated on V8.

### Internal vs. Public API

Expand Down
5 changes: 2 additions & 3 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,9 @@ explicitly via error event handlers set on the domain instead.
<a id="DEP0013"></a>
### DEP0013: fs async function without callback

Type: End-of-Life
Type: Runtime

Calling an asynchronous function without a callback will throw a `TypeError`
v8.0.0 onwards. Refer: [PR 12562](https://github.com/nodejs/node/pull/12562)
Calling an asynchronous function without a callback is deprecated.

<a id="DEP0014"></a>
### DEP0014: fs.read legacy String interface
Expand Down
180 changes: 30 additions & 150 deletions doc/api/fs.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions doc/api/n-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ for the N-API C based functions exported by Node.js. These wrappers are not
part of N-API, nor will they be maintained as part of Node.js. One such
example is: [node-api](https://github.com/nodejs/node-api).

In order to use the N-API functions, include the file
[node_api.h](https://github.com/nodejs/node/blob/master/src/node_api.h)
which is located in the src directory in the node development tree.
For example:
```C
#include <node_api.h>
```

## Basic N-API Data Types

N-API exposes the following fundamental datatypes as abstractions that are
Expand Down
60 changes: 44 additions & 16 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const kMaxLength = require('buffer').kMaxLength;

const isWindows = process.platform === 'win32';

const DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
const errnoException = util._errnoException;

function getOptions(options, defaultOptions) {
Expand Down Expand Up @@ -87,26 +88,48 @@ function copyObject(source) {
return target;
}

var internalErrors;
function lazyErrors() {
if (!internalErrors)
internalErrors = require('internal/errors');
return internalErrors;
function rethrow() {
// TODO(thefourtheye) Throw error instead of warning in major version > 7
process.emitWarning(
'Calling an asynchronous function without callback is deprecated.',
'DeprecationWarning', 'DEP0013', rethrow
);

// Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
// is fairly slow to generate.
if (DEBUG) {
var backtrace = new Error();
return function(err) {
if (err) {
backtrace.stack = err.name + ': ' + err.message +
backtrace.stack.substr(backtrace.name.length);
throw backtrace;
}
};
}

return function(err) {
if (err) {
throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs
}
};
}

function maybeCallback(cb) {
if (typeof cb === 'function')
return cb;
else
throw new (lazyErrors().TypeError)('ERR_INVALID_CALLBACK');
return typeof cb === 'function' ? cb : rethrow();
}

// Ensure that callbacks run in the global context. Only use this function
// for callbacks that are passed to the binding layer, callbacks that are
// invoked from JS already run in the proper scope.
function makeCallback(cb) {
if (typeof cb !== 'function')
throw new (lazyErrors().TypeError)('ERR_INVALID_CALLBACK');
if (cb === undefined) {
return rethrow();
}

if (typeof cb !== 'function') {
throw new TypeError('"callback" argument must be a function');
}

return function() {
return cb.apply(null, arguments);
Expand All @@ -117,8 +140,13 @@ function makeCallback(cb) {
// an optimization, since the data passed back to the callback needs to be
// transformed anyway.
function makeStatsCallback(cb) {
if (typeof cb !== 'function')
throw new (lazyErrors().TypeError)('ERR_INVALID_CALLBACK');
if (cb === undefined) {
return rethrow();
}

if (typeof cb !== 'function') {
throw new TypeError('"callback" argument must be a function');
}

return function(err) {
if (err) return cb(err);
Expand Down Expand Up @@ -240,10 +268,10 @@ fs.access = function(path, mode, callback) {
if (typeof mode === 'function') {
callback = mode;
mode = fs.F_OK;
} else if (typeof callback !== 'function') {
throw new TypeError('"callback" argument must be a function');
}

callback = makeCallback(callback);

if (handleError((path = getPathFromURL(path)), callback))
return;

Expand All @@ -252,7 +280,7 @@ fs.access = function(path, mode, callback) {

mode = mode | 0;
var req = new FSReqWrap();
req.oncomplete = callback;
req.oncomplete = makeCallback(callback);
binding.access(pathModule._makeLong(path), mode, req);
};

Expand Down
7 changes: 5 additions & 2 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4448,8 +4448,11 @@ void Init(int* argc,
// Initialize ICU.
// If icu_data_dir is empty here, it will load the 'minimal' data.
if (!i18n::InitializeICUDirectory(icu_data_dir)) {
FatalError(nullptr, "Could not initialize ICU "
"(check NODE_ICU_DATA or --icu-data-dir parameters)");
fprintf(stderr,
"%s: could not initialize ICU "
"(check NODE_ICU_DATA or --icu-data-dir parameters)",
argv[0]);
exit(9);
}
#endif

Expand Down
2 changes: 1 addition & 1 deletion src/node_api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,7 @@ napi_status napi_get_last_error_info(napi_env env,
error_messages[env->last_error.error_code];

*result = &(env->last_error);
return napi_clear_last_error(env);
return napi_ok;
}

napi_status napi_create_function(napi_env env,
Expand Down
45 changes: 26 additions & 19 deletions src/node_i18n.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
#include <unicode/utypes.h>
#include <unicode/putil.h>
#include <unicode/uchar.h>
#include <unicode/uclean.h>
#include <unicode/udata.h>
#include <unicode/uidna.h>
#include <unicode/ucnv.h>
Expand Down Expand Up @@ -418,28 +419,26 @@ void GetVersion(const FunctionCallbackInfo<Value>& args) {
} // anonymous namespace

bool InitializeICUDirectory(const std::string& path) {
UErrorCode status = U_ZERO_ERROR;
if (path.empty()) {
UErrorCode status = U_ZERO_ERROR;
#ifdef NODE_HAVE_SMALL_ICU
// install the 'small' data.
udata_setCommonData(&SMALL_ICUDATA_ENTRY_POINT, &status);
#else // !NODE_HAVE_SMALL_ICU
// no small data, so nothing to do.
#endif // !NODE_HAVE_SMALL_ICU
return (status == U_ZERO_ERROR);
} else {
u_setDataDirectory(path.c_str());
return true; // No error.
u_init(&status);
}
return status == U_ZERO_ERROR;
}

int32_t ToUnicode(MaybeStackBuffer<char>* buf,
const char* input,
size_t length,
bool lenient) {
size_t length) {
UErrorCode status = U_ZERO_ERROR;
uint32_t options = UIDNA_DEFAULT;
options |= UIDNA_NONTRANSITIONAL_TO_UNICODE;
uint32_t options = UIDNA_NONTRANSITIONAL_TO_UNICODE;
UIDNA* uidna = uidna_openUTS46(options, &status);
if (U_FAILURE(status))
return -1;
Expand All @@ -461,14 +460,10 @@ int32_t ToUnicode(MaybeStackBuffer<char>* buf,
&status);
}

// UTS #46's ToUnicode operation applies no validation of domain name length
// (nor a flag requesting it to do so, like VerifyDnsLength for ToASCII). For
// that reason, unlike ToASCII below, ICU4C correctly accepts long domain
// names. However, ICU4C still sets the EMPTY_LABEL error in contrary to UTS
// #46. Therefore, explicitly filters out that error here.
info.errors &= ~UIDNA_ERROR_EMPTY_LABEL;
// info.errors is ignored as UTS #46 ToUnicode always produces a Unicode
// string, regardless of whether an error occurred.

if (U_FAILURE(status) || (!lenient && info.errors != 0)) {
if (U_FAILURE(status)) {
len = -1;
buf->SetLength(0);
} else {
Expand All @@ -484,8 +479,7 @@ int32_t ToASCII(MaybeStackBuffer<char>* buf,
size_t length,
bool lenient) {
UErrorCode status = U_ZERO_ERROR;
uint32_t options = UIDNA_DEFAULT;
options |= UIDNA_NONTRANSITIONAL_TO_ASCII;
uint32_t options = UIDNA_NONTRANSITIONAL_TO_ASCII | UIDNA_CHECK_BIDI;
UIDNA* uidna = uidna_openUTS46(options, &status);
if (U_FAILURE(status))
return -1;
Expand Down Expand Up @@ -517,6 +511,21 @@ int32_t ToASCII(MaybeStackBuffer<char>* buf,
info.errors &= ~UIDNA_ERROR_LABEL_TOO_LONG;
info.errors &= ~UIDNA_ERROR_DOMAIN_NAME_TOO_LONG;

// These error conditions are mandated unconditionally by UTS #46 version
// 9.0.0 (rev. 17), but were found to be incompatible with actual domain
// names in the wild. As such, in the current UTS #46 draft (rev. 18) these
// checks are made optional depending on the CheckHyphens flag, which will be
// disabled in WHATWG URL's "domain to ASCII" algorithm soon.
// Refs:
// - https://github.com/whatwg/url/issues/53
// - https://github.com/whatwg/url/pull/309
// - http://www.unicode.org/review/pri317/
// - http://www.unicode.org/reports/tr46/tr46-18.html
// - https://www.icann.org/news/announcement-2000-01-07-en
info.errors &= ~UIDNA_ERROR_HYPHEN_3_4;
info.errors &= ~UIDNA_ERROR_LEADING_HYPHEN;
info.errors &= ~UIDNA_ERROR_TRAILING_HYPHEN;

if (U_FAILURE(status) || (!lenient && info.errors != 0)) {
len = -1;
buf->SetLength(0);
Expand All @@ -533,11 +542,9 @@ static void ToUnicode(const FunctionCallbackInfo<Value>& args) {
CHECK_GE(args.Length(), 1);
CHECK(args[0]->IsString());
Utf8Value val(env->isolate(), args[0]);
// optional arg
bool lenient = args[1]->BooleanValue(env->context()).FromJust();

MaybeStackBuffer<char> buf;
int32_t len = ToUnicode(&buf, *val, val.length(), lenient);
int32_t len = ToUnicode(&buf, *val, val.length());

if (len < 0) {
return env->ThrowError("Cannot convert name to Unicode");
Expand Down
3 changes: 1 addition & 2 deletions src/node_i18n.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ int32_t ToASCII(MaybeStackBuffer<char>* buf,
bool lenient = false);
int32_t ToUnicode(MaybeStackBuffer<char>* buf,
const char* input,
size_t length,
bool lenient = false);
size_t length);

} // namespace i18n
} // namespace node
Expand Down
59 changes: 39 additions & 20 deletions src/node_url.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ enum url_error_cb_args {
// https://infra.spec.whatwg.org/#ascii-tab-or-newline
CHAR_TEST(8, IsASCIITabOrNewline, (ch == '\t' || ch == '\n' || ch == '\r'))

// https://infra.spec.whatwg.org/#c0-control-or-space
CHAR_TEST(8, IsC0ControlOrSpace, (ch >= '\0' && ch <= ' '))

// https://infra.spec.whatwg.org/#ascii-digit
CHAR_TEST(8, IsASCIIDigit, (ch >= '0' && ch <= '9'))

Expand Down Expand Up @@ -1134,15 +1137,45 @@ static inline void ShortenUrlPath(struct url_data* url) {
}

void URL::Parse(const char* input,
const size_t len,
size_t len,
enum url_parse_state state_override,
struct url_data* url,
bool has_url,
const struct url_data* base,
bool has_base) {
const char* p = input;
const char* end = input + len;

if (!has_url) {
for (const char* ptr = p; ptr < end; ptr++) {
if (IsC0ControlOrSpace(*ptr))
p++;
else
break;
}
for (const char* ptr = end - 1; ptr >= p; ptr--) {
if (IsC0ControlOrSpace(*ptr))
end--;
else
break;
}
len = end - p;
}

std::string whitespace_stripped;
whitespace_stripped.reserve(len);
for (const char* ptr = p; ptr < end; ptr++)
if (!IsASCIITabOrNewline(*ptr))
whitespace_stripped += *ptr;

input = whitespace_stripped.c_str();
len = whitespace_stripped.size();
p = input;
end = input + len;

bool atflag = false;
bool sbflag = false;
bool uflag = false;
int wskip = 0;

std::string buffer;
url->scheme.reserve(len);
Expand All @@ -1159,9 +1192,6 @@ void URL::Parse(const char* input,
enum url_parse_state state = has_state_override ? state_override :
kSchemeStart;

const char* p = input;
const char* end = input + len;

if (state < kSchemeStart || state > kFragment) {
url->flags |= URL_FLAGS_INVALID_PARSE_STATE;
return;
Expand All @@ -1171,18 +1201,6 @@ void URL::Parse(const char* input,
const char ch = p < end ? p[0] : kEOL;
const size_t remaining = end == p ? 0 : (end - p - 1);

if (IsASCIITabOrNewline(ch)) {
if (state == kAuthority) {
// It's necessary to keep track of how much whitespace
// is being ignored when in kAuthority state because of
// how the buffer is managed. TODO: See if there's a better
// way
wskip++;
}
p++;
continue;
}

bool special = (url->flags & URL_FLAGS_SPECIAL);
bool cannot_be_base;
const bool special_back_slash = (special && ch == '\\');
Expand Down Expand Up @@ -1500,7 +1518,7 @@ void URL::Parse(const char* input,
url->flags |= URL_FLAGS_FAILED;
return;
}
p -= buffer.size() + 1 + wskip;
p -= buffer.size() + 1;
buffer.clear();
state = kHost;
} else {
Expand Down Expand Up @@ -1892,16 +1910,17 @@ static void Parse(Environment* env,
HandleScope handle_scope(isolate);
Context::Scope context_scope(context);

const bool has_context = context_obj->IsObject();
const bool has_base = base_obj->IsObject();

struct url_data base;
struct url_data url;
if (context_obj->IsObject())
if (has_context)
HarvestContext(env, &url, context_obj.As<Object>());
if (has_base)
HarvestBase(env, &base, base_obj.As<Object>());

URL::Parse(input, len, state_override, &url, &base, has_base);
URL::Parse(input, len, state_override, &url, has_context, &base, has_base);
if ((url.flags & URL_FLAGS_INVALID_PARSE_STATE) ||
((state_override != kUnknownState) &&
(url.flags & URL_FLAGS_TERMINATED)))
Expand Down
Loading

0 comments on commit 4fc607f

Please sign in to comment.