summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoan Touzet <wohali@apache.org>2020-04-18 03:22:28 +0000
committerJoan Touzet <wohali@apache.org>2020-04-20 20:47:00 +0000
commit5b3452c4b5d236c572827bba55b5a96b98f4b1d1 (patch)
tree2c0895bb67d0a0b04d220598dee349108acf0829
parent6474a8e533502845c38a8ac595e602e9801d0b0e (diff)
downloadcouchdb-feat/spidermonkey-68.tar.gz
Incorporate changes from #2786feat/spidermonkey-68
-rw-r--r--.gitignore1
-rw-r--r--src/couch/priv/couch_js/68/http.cpp214
-rw-r--r--src/couch/priv/couch_js/68/main.cpp65
-rw-r--r--src/couch/priv/couch_js/68/utf8.cpp309
-rw-r--r--src/couch/priv/couch_js/68/utf8.h19
-rw-r--r--src/couch/priv/couch_js/68/util.cpp202
-rw-r--r--src/couch/priv/couch_js/68/util.h23
-rw-r--r--src/couch/rebar.config.script2
-rw-r--r--src/couch/test/eunit/couch_js_tests.erl1
9 files changed, 239 insertions, 597 deletions
diff --git a/.gitignore b/.gitignore
index 8a4a6f08d..645817b76 100644
--- a/.gitignore
+++ b/.gitignore
@@ -117,6 +117,7 @@ src/mango/ebin/
src/mango/test/*.pyc
src/mango/nosetests.xml
src/mango/venv/
+src/jwtf/.rebar3/
test/javascript/junit.xml
/_build/
diff --git a/src/couch/priv/couch_js/68/http.cpp b/src/couch/priv/couch_js/68/http.cpp
index a0c73bdc6..20a609701 100644
--- a/src/couch/priv/couch_js/68/http.cpp
+++ b/src/couch/priv/couch_js/68/http.cpp
@@ -19,7 +19,6 @@
#include <js/Initialization.h>
#include <js/MemoryFunctions.h>
#include "config.h"
-#include "utf8.h"
#include "util.h"
// Soft dependency on cURL bindings because they're
@@ -101,7 +100,6 @@ http_check_enabled()
#ifdef XP_WIN
#define strcasecmp _strcmpi
#define strncasecmp _strnicmp
-#define snprintf _snprintf
#endif
@@ -110,7 +108,7 @@ typedef struct curl_slist CurlHeaders;
typedef struct {
int method;
- char* url;
+ std::string url;
CurlHeaders* req_headers;
int16_t last_status;
} HTTPData;
@@ -128,22 +126,15 @@ const char* METHODS[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "COPY", "OPTION
#define OPTIONS 6
-static bool
-go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t blen);
-
-
-/*static JSString*
-str_from_binary(JSContext* cx, char* data, size_t length);
-*/
+static bool go(JSContext* cx, JSObject* obj, HTTPData* http, std::string& body);
bool
http_ctor(JSContext* cx, JSObject* req)
{
- HTTPData* http = NULL;
+ HTTPData* http = new HTTPData();
bool ret = false;
- http = (HTTPData*) malloc(sizeof(HTTPData));
if(!http)
{
JS_ReportErrorUTF8(cx, "Failed to create CouchHTTP instance.");
@@ -151,7 +142,6 @@ http_ctor(JSContext* cx, JSObject* req)
}
http->method = -1;
- http->url = NULL;
http->req_headers = NULL;
http->last_status = -1;
@@ -161,7 +151,7 @@ http_ctor(JSContext* cx, JSObject* req)
goto success;
error:
- if(http) free(http);
+ if(http) delete http;
success:
return ret;
@@ -173,9 +163,8 @@ http_dtor(JSFreeOp* fop, JSObject* obj)
{
HTTPData* http = (HTTPData*) JS_GetPrivate(obj);
if(http) {
- if(http->url) free(http->url);
if(http->req_headers) curl_slist_free_all(http->req_headers);
- free(http);
+ delete http;
}
}
@@ -184,56 +173,50 @@ bool
http_open(JSContext* cx, JSObject* req, JS::Value mth, JS::Value url, JS::Value snc)
{
HTTPData* http = (HTTPData*) JS_GetPrivate(req);
- char* method = NULL;
int methid;
- bool ret = false;
if(!http) {
JS_ReportErrorUTF8(cx, "Invalid CouchHTTP instance.");
- goto done;
+ return false;
}
- if(mth.isUndefined()) {
- JS_ReportErrorUTF8(cx, "You must specify a method.");
- goto done;
+ if(!mth.isString()) {
+ JS_ReportErrorUTF8(cx, "Method must be a string.");
+ return false;
}
- method = enc_string(cx, mth, NULL);
- if(!method) {
+ std::string method;
+ if(!js_to_string(cx, JS::RootedValue(cx, mth), method)) {
JS_ReportErrorUTF8(cx, "Failed to encode method.");
- goto done;
+ return false;
}
for(methid = 0; METHODS[methid] != NULL; methid++) {
- if(strcasecmp(METHODS[methid], method) == 0) break;
+ if(strcasecmp(METHODS[methid], method.c_str()) == 0) break;
}
if(methid > OPTIONS) {
JS_ReportErrorUTF8(cx, "Invalid method specified.");
- goto done;
+ return false;
}
http->method = methid;
- if(url.isUndefined()) {
- JS_ReportErrorUTF8(cx, "You must specify a URL.");
- goto done;
- }
-
- if(http->url != NULL) {
- free(http->url);
- http->url = NULL;
+ if(!url.isString()) {
+ JS_ReportErrorUTF8(cx, "URL must be a string");
+ return false;
}
- http->url = enc_string(cx, url, NULL);
- if(http->url == NULL) {
+ std::string urlstr;
+ if(!js_to_string(cx, JS::RootedValue(cx, url), urlstr)) {
JS_ReportErrorUTF8(cx, "Failed to encode URL.");
- goto done;
+ return false;
}
+ http->url = urlstr;
if(snc.isBoolean() && snc.isTrue()) {
JS_ReportErrorUTF8(cx, "Synchronous flag must be false.");
- goto done;
+ return false;
}
if(http->req_headers) {
@@ -244,11 +227,7 @@ http_open(JSContext* cx, JSObject* req, JS::Value mth, JS::Value url, JS::Value
// Disable Expect: 100-continue
http->req_headers = curl_slist_append(http->req_headers, "Expect:");
- ret = true;
-
-done:
- if(method) free(method);
- return ret;
+ return true;
}
@@ -256,88 +235,60 @@ bool
http_set_hdr(JSContext* cx, JSObject* req, JS::Value name, JS::Value val)
{
HTTPData* http = (HTTPData*) JS_GetPrivate(req);
- char* keystr = NULL;
- char* valstr = NULL;
- char* hdrbuf = NULL;
- size_t hdrlen = -1;
- bool ret = false;
if(!http) {
JS_ReportErrorUTF8(cx, "Invalid CouchHTTP instance.");
- goto done;
+ return false;
}
- if(name.isUndefined())
+ if(!name.isString())
{
- JS_ReportErrorUTF8(cx, "You must speciy a header name.");
- goto done;
+ JS_ReportErrorUTF8(cx, "Header names must be strings.");
+ return false;
}
- keystr = enc_string(cx, name, NULL);
- if(!keystr)
+ std::string keystr;
+ if(!js_to_string(cx, JS::RootedValue(cx, name), keystr))
{
JS_ReportErrorUTF8(cx, "Failed to encode header name.");
- goto done;
+ return false;
}
- if(val.isUndefined())
+ if(!val.isString())
{
- JS_ReportErrorUTF8(cx, "You must specify a header value.");
- goto done;
+ JS_ReportErrorUTF8(cx, "Header values must be strings.");
+ return false;
}
- valstr = enc_string(cx, val, NULL);
- if(!valstr)
- {
+ std::string valstr;
+ if(!js_to_string(cx, JS::RootedValue(cx, val), valstr)) {
JS_ReportErrorUTF8(cx, "Failed to encode header value.");
- goto done;
- }
-
- hdrlen = strlen(keystr) + strlen(valstr) + 3;
- hdrbuf = (char*) malloc(hdrlen * sizeof(char));
- if(!hdrbuf) {
- JS_ReportErrorUTF8(cx, "Failed to allocate header buffer.");
- goto done;
+ return false;
}
- snprintf(hdrbuf, hdrlen, "%s: %s", keystr, valstr);
- http->req_headers = curl_slist_append(http->req_headers, hdrbuf);
-
- ret = true;
+ std::string header = keystr + ": " + valstr;
+ http->req_headers = curl_slist_append(http->req_headers, header.c_str());
-done:
- if(keystr) free(keystr);
- if(valstr) free(valstr);
- if(hdrbuf) free(hdrbuf);
- return ret;
+ return true;
}
bool
http_send(JSContext* cx, JSObject* req, JS::Value body)
{
HTTPData* http = (HTTPData*) JS_GetPrivate(req);
- char* bodystr = NULL;
- size_t bodylen = 0;
- bool ret = false;
if(!http) {
JS_ReportErrorUTF8(cx, "Invalid CouchHTTP instance.");
- goto done;
+ return false;
}
- if(!body.isUndefined()) {
- bodystr = enc_string(cx, body, &bodylen);
- if(!bodystr) {
- JS_ReportErrorUTF8(cx, "Failed to encode body.");
- goto done;
- }
+ std::string bodystr;
+ if(!js_to_string(cx, JS::RootedValue(cx, body), bodystr)) {
+ JS_ReportErrorUTF8(cx, "Failed to encode body.");
+ return false;
}
- ret = go(cx, req, http, bodystr, bodylen);
-
-done:
- if(bodystr) free(bodystr);
- return ret;
+ return go(cx, req, http, bodystr);
}
int
@@ -397,7 +348,7 @@ typedef struct {
HTTPData* http;
JSContext* cx;
JSObject* resp_headers;
- char* sendbuf;
+ const char* sendbuf;
size_t sendlen;
size_t sent;
int sent_once;
@@ -419,10 +370,9 @@ static size_t recv_body(void *ptr, size_t size, size_t nmem, void *data);
static size_t recv_header(void *ptr, size_t size, size_t nmem, void *data);
static bool
-go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
+go(JSContext* cx, JSObject* obj, HTTPData* http, std::string& body)
{
CurlState state;
- char* referer;
JSString* jsbody;
bool ret = false;
JS::Value tmp;
@@ -433,8 +383,8 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
state.cx = cx;
state.http = http;
- state.sendbuf = body;
- state.sendlen = bodylen;
+ state.sendbuf = body.c_str();;
+ state.sendlen = body.size();
state.sent = 0;
state.sent_once = 0;
@@ -465,13 +415,13 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
tmp = JS_GetReservedSlot(obj, 0);
- if(!(referer = enc_string(cx, tmp, NULL))) {
+ std::string referer;
+ if(!js_to_string(cx, JS::RootedValue(cx, tmp), referer)) {
JS_ReportErrorUTF8(cx, "Failed to encode referer.");
if(state.recvbuf) JS_free(cx, state.recvbuf);
- return ret;
+ return ret;
}
- curl_easy_setopt(HTTP_HANDLE, CURLOPT_REFERER, referer);
- free(referer);
+ curl_easy_setopt(HTTP_HANDLE, CURLOPT_REFERER, referer.c_str());
if(http->method < 0 || http->method > OPTIONS) {
JS_ReportErrorUTF8(cx, "INTERNAL: Unknown method.");
@@ -492,15 +442,15 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0);
}
- if(body && bodylen) {
- curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, bodylen);
+ if(body.size() > 0) {
+ curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, body.size());
} else {
curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, 0);
}
// curl_easy_setopt(HTTP_HANDLE, CURLOPT_VERBOSE, 1);
- curl_easy_setopt(HTTP_HANDLE, CURLOPT_URL, http->url);
+ curl_easy_setopt(HTTP_HANDLE, CURLOPT_URL, http->url.c_str());
curl_easy_setopt(HTTP_HANDLE, CURLOPT_HTTPHEADER, http->req_headers);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_READDATA, &state);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKDATA, &state);
@@ -534,7 +484,8 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
if(state.recvbuf) {
state.recvbuf[state.read] = '\0';
- jsbody = dec_string(cx, state.recvbuf, state.read+1);
+ std::string bodystr(state.recvbuf, state.read);
+ jsbody = string_to_js(cx, bodystr);
if(!jsbody) {
// If we can't decode the body as UTF-8 we forcefully
// convert it to a string by just forcing each byte
@@ -574,7 +525,7 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
static size_t
send_body(void *ptr, size_t size, size_t nmem, void *data)
{
- CurlState* state = (CurlState*) data;
+ CurlState* state = static_cast<CurlState*>(data);
size_t length = size * nmem;
size_t towrite = state->sendlen - state->sent;
@@ -600,19 +551,19 @@ send_body(void *ptr, size_t size, size_t nmem, void *data)
static int
seek_body(void* ptr, curl_off_t offset, int origin)
{
- CurlState* state = (CurlState*) ptr;
+ CurlState* state = static_cast<CurlState*>(ptr);
if(origin != SEEK_SET) return -1;
- state->sent = (size_t) offset;
- return (int) state->sent;
+ state->sent = static_cast<size_t>(offset);
+ return static_cast<int>(state->sent);
}
static size_t
recv_header(void *ptr, size_t size, size_t nmem, void *data)
{
- CurlState* state = (CurlState*) data;
+ CurlState* state = static_cast<CurlState*>(data);
char code[4];
- char* header = (char*) ptr;
+ char* header = static_cast<char*>(ptr);
size_t length = size * nmem;
JSString* hdr = NULL;
uint32_t hdrlen;
@@ -640,7 +591,8 @@ recv_header(void *ptr, size_t size, size_t nmem, void *data)
}
// Append the new header to our array.
- hdr = dec_string(state->cx, header, length);
+ std::string hdrstr(header, length);
+ hdr = string_to_js(state->cx, hdrstr);
if(!hdr) {
return CURLE_WRITE_ERROR;
}
@@ -661,14 +613,17 @@ recv_header(void *ptr, size_t size, size_t nmem, void *data)
static size_t
recv_body(void *ptr, size_t size, size_t nmem, void *data)
{
- CurlState* state = (CurlState*) data;
+ CurlState* state = static_cast<CurlState*>(data);
size_t length = size * nmem;
char* tmp = NULL;
if(!state->recvbuf) {
state->recvlen = 4096;
state->read = 0;
- state->recvbuf = static_cast<char *>(JS_malloc(state->cx, state->recvlen));
+ state->recvbuf = static_cast<char*>(JS_malloc(
+ state->cx,
+ state->recvlen
+ ));
}
if(!state->recvbuf) {
@@ -678,7 +633,12 @@ recv_body(void *ptr, size_t size, size_t nmem, void *data)
// +1 so we can add '\0' back up in the go function.
size_t oldlen = state->recvlen;
while(length+1 > state->recvlen - state->read) state->recvlen *= 2;
- tmp = static_cast<char *>(JS_realloc(state->cx, state->recvbuf, oldlen, state->recvlen));
+ tmp = static_cast<char*>(JS_realloc(
+ state->cx,
+ state->recvbuf,
+ oldlen,
+ state->recvlen
+ ));
if(!tmp) return CURLE_WRITE_ERROR;
state->recvbuf = tmp;
@@ -687,24 +647,4 @@ recv_body(void *ptr, size_t size, size_t nmem, void *data)
return length;
}
-/*JSString*
-str_from_binary(JSContext* cx, char* data, size_t length)
-{
- char16_t* conv = static_cast<char16_t *>(JS_malloc(cx, length * sizeof(char16_t)));
- JSString* ret = NULL;
- size_t i;
-
- if(!conv) return NULL;
-
- for(i = 0; i < length; i++) {
- conv[i] = (char16_t) data[i];
- }
-
- ret = JS_NewUCString(cx, conv, length);
- if(!ret) JS_free(cx, conv);
-
- return ret;
-}
-*/
-
#endif /* HAVE_CURL */
diff --git a/src/couch/priv/couch_js/68/main.cpp b/src/couch/priv/couch_js/68/main.cpp
index 3860a01a8..2c95f6129 100644
--- a/src/couch/priv/couch_js/68/main.cpp
+++ b/src/couch/priv/couch_js/68/main.cpp
@@ -31,7 +31,6 @@
#include "config.h"
#include "http.h"
-#include "utf8.h"
#include "util.h"
static bool enableSharedMemory = true;
@@ -102,7 +101,10 @@ req_ctor(JSContext* cx, unsigned int argc, JS::Value* vp)
static bool
req_open(JSContext* cx, unsigned int argc, JS::Value* vp)
{
- GET_THIS(cx, argc, vp, args, obj)
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::RootedObject obj(cx);
+ if (!args.computeThis(cx, &obj))
+ return false;
bool ret = false;
if(argc == 2) {
@@ -121,7 +123,10 @@ req_open(JSContext* cx, unsigned int argc, JS::Value* vp)
static bool
req_set_hdr(JSContext* cx, unsigned int argc, JS::Value* vp)
{
- GET_THIS(cx, argc, vp, args, obj)
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::RootedObject obj(cx);
+ if (!args.computeThis(cx, &obj))
+ return false;
bool ret = false;
if(argc == 2) {
@@ -138,7 +143,10 @@ req_set_hdr(JSContext* cx, unsigned int argc, JS::Value* vp)
static bool
req_send(JSContext* cx, unsigned int argc, JS::Value* vp)
{
- GET_THIS(cx, argc, vp, args, obj)
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::RootedObject obj(cx);
+ if (!args.computeThis(cx, &obj))
+ return false;
bool ret = false;
if(argc == 1) {
@@ -154,7 +162,11 @@ req_send(JSContext* cx, unsigned int argc, JS::Value* vp)
static bool
req_status(JSContext* cx, unsigned int argc, JS::Value* vp)
{
- GET_THIS(cx, argc, vp, args, obj)
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::RootedObject obj(cx);
+ if (!args.computeThis(cx, &obj))
+ return false;
+
int status = http_status(cx, obj);
if(status < 0)
@@ -167,8 +179,12 @@ req_status(JSContext* cx, unsigned int argc, JS::Value* vp)
static bool
base_url(JSContext *cx, unsigned int argc, JS::Value* vp)
{
- GET_THIS(cx, argc, vp, args, obj)
- couch_args *cargs = (couch_args*)JS_GetContextPrivate(cx);
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::RootedObject obj(cx);
+ if (!args.computeThis(cx, &obj))
+ return false;
+
+ couch_args *cargs = static_cast<couch_args*>(JS_GetContextPrivate(cx));
JS::Value uri_val;
bool rc = http_uri(cx, obj, cargs, &uri_val);
args.rval().set(uri_val);
@@ -278,7 +294,19 @@ static bool
print(JSContext* cx, unsigned int argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- couch_print(cx, argc, args);
+
+ bool use_stderr = false;
+ if(argc > 1 && args[1].isTrue()) {
+ use_stderr = true;
+ }
+
+ if(!args[0].isString()) {
+ JS_ReportErrorUTF8(cx, "Unable to print non-string value.");
+ return false;
+ }
+
+ couch_print(cx, args[0], use_stderr);
+
args.rval().setUndefined();
return true;
}
@@ -381,7 +409,7 @@ static JSFunctionSpec global_functions[] = {
static bool
csp_allows(JSContext* cx, JS::HandleValue code)
{
- couch_args *args = (couch_args*)JS_GetContextPrivate(cx);
+ couch_args* args = static_cast<couch_args*>(JS_GetContextPrivate(cx));
if(args->eval) {
return true;
} else {
@@ -476,14 +504,27 @@ main(int argc, const char* argv[])
script = JS::CompileUtf8File(cx, options, fp);
fclose(fp);
if (!script) {
- fprintf(stderr, "Failed to compile file: %s\n", filename);
+ JS::RootedValue exc(cx);
+ if(!JS_GetPendingException(cx, &exc)) {
+ fprintf(stderr, "Failed to compile file: %s\n", filename);
+ } else {
+ JS::RootedObject exc_obj(cx, &exc.toObject());
+ JSErrorReport* report = JS_ErrorFromException(cx, exc_obj);
+ couch_error(cx, report);
+ }
return 1;
}
JS::RootedValue result(cx);
if(JS_ExecuteScript(cx, script, &result) != true) {
- fprintf(stderr, "Failed to execute script.\n");
- return 1;
+ JS::RootedValue exc(cx);
+ if(!JS_GetPendingException(cx, &exc)) {
+ fprintf(stderr, "Failed to execute script.\n");
+ } else {
+ JS::RootedObject exc_obj(cx, &exc.toObject());
+ JSErrorReport* report = JS_ErrorFromException(cx, exc_obj);
+ couch_error(cx, report);
+ }
}
// Give the GC a chance to run.
diff --git a/src/couch/priv/couch_js/68/utf8.cpp b/src/couch/priv/couch_js/68/utf8.cpp
deleted file mode 100644
index c28e026f7..000000000
--- a/src/couch/priv/couch_js/68/utf8.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#include <jsapi.h>
-#include <js/Initialization.h>
-#include <js/Conversions.h>
-#include <js/MemoryFunctions.h>
-#include <js/Wrapper.h>
-#include "config.h"
-#include "util.h"
-
-static int
-enc_char(uint8_t *utf8Buffer, uint32_t ucs4Char)
-{
- int utf8Length = 1;
-
- if (ucs4Char < 0x80)
- {
- *utf8Buffer = (uint8_t)ucs4Char;
- }
- else
- {
- int i;
- uint32_t a = ucs4Char >> 11;
- utf8Length = 2;
- while(a)
- {
- a >>= 5;
- utf8Length++;
- }
- i = utf8Length;
- while(--i)
- {
- utf8Buffer[i] = (uint8_t)((ucs4Char & 0x3F) | 0x80);
- ucs4Char >>= 6;
- }
- *utf8Buffer = (uint8_t)(0x100 - (1 << (8-utf8Length)) + ucs4Char);
- }
-
- return utf8Length;
-}
-
-static bool
-enc_charbuf(const char16_t* src, size_t srclen, char* dst, size_t* dstlenp)
-{
- size_t i;
- size_t utf8Len;
- size_t dstlen = *dstlenp;
- size_t origDstlen = dstlen;
- char16_t c;
- char16_t c2;
- uint32_t v;
- uint8_t utf8buf[6];
-
- if(!dst)
- {
- dstlen = origDstlen = (size_t) -1;
- }
-
- while(srclen)
- {
- c = *src++;
- srclen--;
-
- if(c <= 0xD7FF || c >= 0xE000)
- {
- v = (uint32_t) c;
- }
- else if(c >= 0xD800 && c <= 0xDBFF)
- {
- if(srclen < 1) goto buffer_too_small;
- c2 = *src++;
- srclen--;
- if(c2 >= 0xDC00 && c2 <= 0xDFFF)
- {
- v = (uint32_t) (((c - 0xD800) << 10) + (c2 - 0xDC00) + 0x10000);
- }
- else
- {
- // Invalid second half of surrogate pair
- v = (uint32_t) 0xFFFD;
- // Undo our character advancement
- src--;
- srclen++;
- }
- }
- else
- {
- // Invalid first half surrogate pair
- v = (uint32_t) 0xFFFD;
- }
-
- if(v < 0x0080)
- {
- // no encoding necessary - performance hack
- if(!dstlen) goto buffer_too_small;
- if(dst) *dst++ = (char) v;
- utf8Len = 1;
- }
- else
- {
- utf8Len = enc_char(utf8buf, v);
- if(utf8Len > dstlen) goto buffer_too_small;
- if(dst)
- {
- for (i = 0; i < utf8Len; i++)
- {
- *dst++ = (char) utf8buf[i];
- }
- }
- }
- dstlen -= utf8Len;
- }
-
- *dstlenp = (origDstlen - dstlen);
- return true;
-
-buffer_too_small:
- *dstlenp = (origDstlen - dstlen);
- return false;
-}
-
-char*
-enc_string(JSContext* cx, JS::Value arg, size_t* buflen)
-{
- JSString* str = NULL;
- const char16_t* src = NULL;
- char* bytes = NULL;
- size_t srclen = 0;
- size_t byteslen = 0;
- JS::AutoStableStringChars rawChars(cx);
-
- str = arg.toString();
- if(!str) goto error;
-
- if (!rawChars.initTwoByte(cx, str))
- return NULL;
-
- src = rawChars.twoByteRange().begin().get();
- srclen = JS_GetStringLength(str);
-
- if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
-
- bytes = js_pod_malloc<char>(byteslen + 1);
- bytes[byteslen] = 0;
-
- if(!enc_charbuf(src, srclen, bytes, &byteslen)) goto error;
-
- if(buflen) *buflen = byteslen;
- goto success;
-
-error:
- if(bytes != NULL) JS_free(cx, bytes);
- bytes = NULL;
-
-success:
-/*
- JS::RootedString str(cx, arg.toString());
- JS::UniqueChars chars = JS_EncodeStringToUTF8(cx, str);
-
- if(buflen) *buflen = strlen(chars.get());
-
- return JS_NewUCStringCopyN(cs, chars.get(), buflen);
-*/
- return bytes;
-}
-
-static uint32_t
-dec_char(const uint8_t *utf8Buffer, int utf8Length)
-{
- uint32_t ucs4Char;
- uint32_t minucs4Char;
-
- // from Unicode 3.1, non-shortest form is illegal
- static const uint32_t minucs4Table[] = {
- 0x00000080, 0x00000800, 0x0001000, 0x0020000, 0x0400000
- };
-
- if (utf8Length == 1)
- {
- ucs4Char = *utf8Buffer;
- }
- else
- {
- ucs4Char = *utf8Buffer++ & ((1<<(7-utf8Length))-1);
- minucs4Char = minucs4Table[utf8Length-2];
- while(--utf8Length)
- {
- ucs4Char = ucs4Char<<6 | (*utf8Buffer++ & 0x3F);
- }
- if(ucs4Char < minucs4Char || ucs4Char == 0xFFFE || ucs4Char == 0xFFFF)
- {
- ucs4Char = 0xFFFD;
- }
- }
-
- return ucs4Char;
-}
-
-static bool
-dec_charbuf(const char *src, size_t srclen, char16_t *dst, size_t *dstlenp)
-{
- uint32_t v;
- size_t offset = 0;
- size_t j;
- size_t n;
- size_t dstlen = *dstlenp;
- size_t origDstlen = dstlen;
-
- if(!dst) dstlen = origDstlen = (size_t) -1;
-
- while(srclen)
- {
- v = (uint8_t) *src;
- n = 1;
-
- if(v & 0x80)
- {
- while(v & (0x80 >> n))
- {
- n++;
- }
-
- if(n > srclen) goto buffer_too_small;
- if(n == 1 || n > 6) goto bad_character;
-
- for(j = 1; j < n; j++)
- {
- if((src[j] & 0xC0) != 0x80) goto bad_character;
- }
-
- v = dec_char((const uint8_t *) src, n);
- if(v >= 0x10000)
- {
- v -= 0x10000;
-
- if(v > 0xFFFFF || dstlen < 2)
- {
- *dstlenp = (origDstlen - dstlen);
- return false;
- }
-
- if(dstlen < 2) goto buffer_too_small;
-
- if(dst)
- {
- *dst++ = (char16_t)((v >> 10) + 0xD800);
- v = (char16_t)((v & 0x3FF) + 0xDC00);
- }
- dstlen--;
- }
- }
-
- if(!dstlen) goto buffer_too_small;
- if(dst) *dst++ = (char16_t) v;
-
- dstlen--;
- offset += n;
- src += n;
- srclen -= n;
- }
-
- *dstlenp = (origDstlen - dstlen);
- return true;
-
-bad_character:
- *dstlenp = (origDstlen - dstlen);
- return false;
-
-buffer_too_small:
- *dstlenp = (origDstlen - dstlen);
- return false;
-}
-
-JSString*
-dec_string(JSContext* cx, const char* bytes, size_t byteslen)
-{
- JSString* str = NULL;
- size_t charslen;
-
- if(!dec_charbuf(bytes, byteslen, NULL, &charslen)) return NULL;
-
- JS::UniqueTwoByteChars chars(js_pod_malloc<char16_t>(charslen + 1));
- if(!chars) return NULL;
- chars.get()[charslen] = 0;
-
- if(!dec_charbuf(bytes, byteslen, chars.get(), &charslen)) goto error;
-
- str = JS_NewUCString(cx, std::move(chars), charslen - 1);
- if(!str) goto error;
-
- goto success;
-
-error:
- if(chars != NULL) JS_free(cx, chars.get());
- str = NULL;
-
-success:
- return str;
-}
diff --git a/src/couch/priv/couch_js/68/utf8.h b/src/couch/priv/couch_js/68/utf8.h
deleted file mode 100644
index c8b1f4d82..000000000
--- a/src/couch/priv/couch_js/68/utf8.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#ifndef COUCH_JS_UTF_8_H
-#define COUCH_JS_UTF_8_H
-
-char* enc_string(JSContext* cx, JS::Value arg, size_t* buflen);
-JSString* dec_string(JSContext* cx, const char* buf, size_t buflen);
-
-#endif
diff --git a/src/couch/priv/couch_js/68/util.cpp b/src/couch/priv/couch_js/68/util.cpp
index f941e7dd2..7717f1185 100644
--- a/src/couch/priv/couch_js/68/util.cpp
+++ b/src/couch/priv/couch_js/68/util.cpp
@@ -13,7 +13,11 @@
#include <stdlib.h>
#include <string.h>
+#include <sstream>
+
#include <jsapi.h>
+#include <jsfriendapi.h>
+#include <js/CharacterEncoding.h>
#include <js/Conversions.h>
#include <js/Initialization.h>
#include <js/MemoryFunctions.h>
@@ -21,53 +25,57 @@
#include "help.h"
#include "util.h"
-#include "utf8.h"
-/*
std::string
js_to_string(JSContext* cx, JS::HandleValue val)
{
+ JS::AutoSaveExceptionState exc_state(cx);
JS::RootedString sval(cx);
sval = val.toString();
JS::UniqueChars chars(JS_EncodeStringToUTF8(cx, sval));
if(!chars) {
JS_ClearPendingException(cx);
- fprintf(stderr, "Error converting value to string.\n");
- exit(3);
+ return std::string();
}
return chars.get();
}
-std::string
-js_to_string(JSContext* cx, JSString *str)
+bool
+js_to_string(JSContext* cx, JS::HandleValue val, std::string& str)
{
- JS::UniqueChars chars(JS_EncodeString(cx, str));
- if(!chars) {
- JS_ClearPendingException(cx);
- fprintf(stderr, "Error converting to string.\n");
- exit(3);
+ if(!val.isString()) {
+ return false;
}
- return chars.get();
+ if(JS_GetStringLength(val.toString()) == 0) {
+ str = "";
+ return true;
+ }
+
+ std::string conv = js_to_string(cx, val);
+ if(!conv.size()) {
+ return false;
+ }
+
+ str = conv;
+ return true;
}
-*/
JSString*
-string_to_js(JSContext* cx, const std::string& s)
+string_to_js(JSContext* cx, const std::string& raw)
{
-/*
+ JS::UTF8Chars utf8(raw.c_str(), raw.size());
+ JS::UniqueTwoByteChars utf16;
+ size_t len;
- JSString* ret = JS_NewStringCopyN(cx, s.c_str(), s.size());
- if(ret != nullptr) {
- return ret;
+ utf16.reset(JS::UTF8CharsToNewTwoByteCharsZ(cx, utf8, &len, js::MallocArena).get());
+ if(!utf16) {
+ return nullptr;
}
- fprintf(stderr, "Unable to allocate string object.\n");
- exit(3);
-*/
- return dec_string(cx, s.c_str(), s.size());
+ return JS_NewUCString(cx, std::move(utf16), len);
}
size_t
@@ -92,21 +100,21 @@ couch_readfile(const char* file, char** outbuf_p)
while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
if(buf == NULL) {
- buf = (char*) malloc(nread + 1);
+ buf = new char[nread + 1];
if(buf == NULL) {
fprintf(stderr, "Out of memory.\n");
exit(3);
}
memcpy(buf, fbuf, nread);
} else {
- tmp = (char*) malloc(buflen + nread + 1);
+ tmp = new char[buflen + nread + 1];
if(tmp == NULL) {
fprintf(stderr, "Out of memory.\n");
exit(3);
}
memcpy(tmp, buf, buflen);
memcpy(tmp+buflen, fbuf, nread);
- free(buf);
+ delete buf;
buf = tmp;
}
buflen += nread;
@@ -122,12 +130,17 @@ couch_parse_args(int argc, const char* argv[])
couch_args* args;
int i = 1;
- args = (couch_args*) malloc(sizeof(couch_args));
+ args = new couch_args();
if(args == NULL)
return NULL;
- memset(args, '\0', sizeof(couch_args));
+ args->eval = 0;
+ args->use_http = 0;
+ args->use_test_funs = 0;
args->stack_size = 64L * 1024L * 1024L;
+ args->scripts = nullptr;
+ args->uri_file = nullptr;
+ args->uri = nullptr;
while(i < argc) {
if(strcmp("-h", argv[i]) == 0) {
@@ -200,9 +213,8 @@ couch_readline(JSContext* cx, FILE* fp)
size_t byteslen = 256;
size_t oldbyteslen = 256;
size_t readlen = 0;
- bool sawNewline = false;
- bytes = static_cast<char *>(JS_malloc(cx, byteslen));
+ bytes = static_cast<char*>(JS_malloc(cx, byteslen));
if(bytes == NULL) return NULL;
while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) {
@@ -210,14 +222,13 @@ couch_readline(JSContext* cx, FILE* fp)
if(bytes[used-1] == '\n') {
bytes[used-1] = '\0';
- sawNewline = true;
break;
}
// Double our buffer and read more.
oldbyteslen = byteslen;
byteslen *= 2;
- tmp = static_cast<char *>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
+ tmp = static_cast<char*>(JS_realloc(cx, bytes, oldbyteslen, byteslen));
if(!tmp) {
JS_free(cx, bytes);
return NULL;
@@ -233,7 +244,7 @@ couch_readline(JSContext* cx, FILE* fp)
}
// Shrink the buffer to the actual data size
- tmp = static_cast<char *>(JS_realloc(cx, bytes, byteslen, used));
+ tmp = static_cast<char*>(JS_realloc(cx, bytes, byteslen, used));
if(!tmp) {
JS_free(cx, bytes);
return NULL;
@@ -241,37 +252,22 @@ couch_readline(JSContext* cx, FILE* fp)
bytes = tmp;
byteslen = used;
- str = string_to_js(cx, std::string(tmp, byteslen));
+ str = string_to_js(cx, std::string(tmp));
JS_free(cx, bytes);
return str;
}
void
-couch_print(JSContext* cx, unsigned int argc, JS::CallArgs argv)
+couch_print(JSContext* cx, JS::HandleValue obj, bool use_stderr)
{
FILE *stream = stdout;
- if (argc) {
- if (argc > 1 && argv[1].isTrue()) {
- stream = stderr;
- }
- JS::AutoSaveExceptionState exc_state(cx);
- JS::RootedString sval(cx, JS::ToString(cx, argv[0]));
- if (!sval) {
- fprintf(stream, "couch_print: <cannot convert value to string>\n");
- fflush(stream);
- return;
- }
- JS::UniqueChars bytes(JS_EncodeStringToUTF8(cx, sval));
- if (!bytes)
- return;
-
- fprintf(stream, "%s", bytes.get());
- exc_state.restore();
+ if (use_stderr) {
+ stream = stderr;
}
-
- fputc('\n', stream);
+ std::string val = js_to_string(cx, obj);
+ fprintf(stream, "%s\n", val.c_str());
fflush(stream);
}
@@ -279,52 +275,64 @@ couch_print(JSContext* cx, unsigned int argc, JS::CallArgs argv)
void
couch_error(JSContext* cx, JSErrorReport* report)
{
- JS::RootedValue v(cx), stack(cx), replace(cx);
- char* bytes;
- JSObject* regexp;
-
- if(!report || !JSREPORT_IS_WARNING(report->flags))
- {
- fprintf(stderr, "%s\n", report->message().c_str());
-
- // Print a stack trace, if available.
- if (JSREPORT_IS_EXCEPTION(report->flags) &&
- JS_GetPendingException(cx, &v))
- {
- // Clear the exception before an JS method calls or the result is
- // infinite, recursive error report generation.
- JS_ClearPendingException(cx);
-
- // Use JS regexp to indent the stack trace.
- // If the regexp can't be created, don't JS_ReportErrorUTF8 since it is
- // probably not productive to wind up here again.
- JS::RootedObject vobj(cx, v.toObjectOrNull());
-
- if(JS_GetProperty(cx, vobj, "stack", &stack) &&
- (regexp = JS::NewRegExpObject(
- cx, "^(?=.)", 6, JS::RegExpFlag::Global | JS::RegExpFlag::Multiline)))
-
- {
- // Set up the arguments to ``String.replace()``
- JS::RootedValueVector re_args(cx);
- JS::RootedValue arg0(cx, JS::ObjectValue(*regexp));
- auto arg1 = JS::StringValue(string_to_js(cx, "\t"));
-
- if (re_args.append(arg0) && re_args.append(arg1)) {
- // Perform the replacement
- JS::RootedObject sobj(cx, stack.toObjectOrNull());
- if(JS_GetProperty(cx, sobj, "replace", &replace) &&
- JS_CallFunctionValue(cx, sobj, replace, re_args, &v))
- {
- // Print the result
- bytes = enc_string(cx, v, NULL);
- fprintf(stderr, "Stacktrace:\n%s", bytes);
- JS_free(cx, bytes);
- }
- }
- }
+ if(!report) {
+ return;
+ }
+
+ if(JSREPORT_IS_WARNING(report->flags)) {
+ return;
+ }
+
+ std::ostringstream msg;
+ msg << "error: " << report->message().c_str();
+
+ mozilla::Maybe<JSAutoRealm> ar;
+ JS::RootedValue exc(cx);
+ JS::RootedObject exc_obj(cx);
+ JS::RootedObject stack_obj(cx);
+ JS::RootedString stack_str(cx);
+ JS::RootedValue stack_val(cx);
+ JSPrincipals* principals = GetRealmPrincipals(js::GetContextRealm(cx));
+
+ if(!JS_GetPendingException(cx, &exc)) {
+ goto done;
+ }
+
+ // Clear the exception before an JS method calls or the result is
+ // infinite, recursive error report generation.
+ JS_ClearPendingException(cx);
+
+ exc_obj.set(exc.toObjectOrNull());
+ stack_obj.set(JS::ExceptionStackOrNull(exc_obj));
+
+ if(!stack_obj) {
+ // Compilation errors don't have a stack
+
+ msg << " at ";
+
+ if(report->filename) {
+ msg << report->filename;
+ } else {
+ msg << "<unknown>";
}
+
+ if(report->lineno) {
+ msg << ':' << report->lineno << ':' << report->column;
+ }
+
+ goto done;
}
+
+ if(!JS::BuildStackString(cx, principals, stack_obj, &stack_str, 2)) {
+ goto done;
+ }
+
+ stack_val.set(JS::StringValue(stack_str));
+ msg << std::endl << std::endl << js_to_string(cx, stack_val).c_str();
+
+done:
+ msg << std::endl;
+ fprintf(stderr, "%s", msg.str().c_str());
}
diff --git a/src/couch/priv/couch_js/68/util.h b/src/couch/priv/couch_js/68/util.h
index dc8a3a7b4..bd7843eb9 100644
--- a/src/couch/priv/couch_js/68/util.h
+++ b/src/couch/priv/couch_js/68/util.h
@@ -25,36 +25,17 @@ typedef struct {
JSString* uri;
} couch_args;
-/*
std::string js_to_string(JSContext* cx, JS::HandleValue val);
-std::string js_to_string(JSContext* cx, JSString *str);
+bool js_to_string(JSContext* cx, JS::HandleValue val, std::string& str);
JSString* string_to_js(JSContext* cx, const std::string& s);
-*/
couch_args* couch_parse_args(int argc, const char* argv[]);
int couch_fgets(char* buf, int size, FILE* fp);
JSString* couch_readline(JSContext* cx, FILE* fp);
size_t couch_readfile(const char* file, char** outbuf_p);
-void couch_print(JSContext* cx, unsigned int argc, JS::CallArgs argv);
+void couch_print(JSContext* cx, JS::HandleValue str, bool use_stderr);
void couch_error(JSContext* cx, JSErrorReport* report);
void couch_oom(JSContext* cx, void* data);
bool couch_load_funcs(JSContext* cx, JS::HandleObject obj, JSFunctionSpec* funcs);
-/*
- * GET_THIS:
- * @cx: JSContext pointer passed into JSNative function
- * @argc: Number of arguments passed into JSNative function
- * @vp: Argument value array passed into JSNative function
- * @args: Name for JS::CallArgs variable defined by this code snippet
- * @to: Name for JS::RootedObject variable referring to function's this
- *
- * A convenience macro for getting the 'this' object a function was called with.
- * Use in any JSNative function.
- */
-#define GET_THIS(cx, argc, vp, args, to) \
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
- JS::RootedObject to(cx); \
- if (!args.computeThis(cx, &to)) \
- return false;
-
#endif // Included util.h
diff --git a/src/couch/rebar.config.script b/src/couch/rebar.config.script
index 89c652a58..ad897e8e3 100644
--- a/src/couch/rebar.config.script
+++ b/src/couch/rebar.config.script
@@ -41,7 +41,7 @@ end.
GitSha = case os:getenv("COUCHDB_GIT_SHA") of
false ->
- ""; % release builds won’t get a fallback
+ ""; % release builds won't get a fallback
GitSha0 ->
string:strip(GitSha0, right)
end.
diff --git a/src/couch/test/eunit/couch_js_tests.erl b/src/couch/test/eunit/couch_js_tests.erl
index c2c62463b..693cd9772 100644
--- a/src/couch/test/eunit/couch_js_tests.erl
+++ b/src/couch/test/eunit/couch_js_tests.erl
@@ -137,7 +137,6 @@ should_allow_js_string_mutations() ->
true = couch_query_servers:proc_prompt(Proc, [<<"add_fun">>, Src3]),
Doc = {[{<<"value">>, MomWashedTheFrame}]},
Result = couch_query_servers:proc_prompt(Proc, [<<"map_doc">>, Doc]),
- io:format(standard_error, "~w~n~w~n", [MomWashedTheFrame, Result]),
Expect = [
[[<<"length">>, 14]],
[[<<"substring">>, Washed]],