summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2011-10-06 10:39:21 +0100
committerRobert Newson <rnewson@apache.org>2011-10-06 10:39:21 +0100
commit5b558c81ed9709fb286a6821e9ae6d6478012c2c (patch)
treedf5689ac2ecfda77d4129a4c814dc21f68b93653
parente6c0fc955ea2be0fd3c4e894fd0c7cc87202c5a5 (diff)
Remove SpiderMonkey 1.8.5 compatibility
This commit reverts 1.8.5 compatibility including the corresponding couchjs paren hack as this leads to significant breakage in existing functions.
-rw-r--r--configure.ac41
-rw-r--r--share/server/mimeparse.js2
-rw-r--r--share/server/util.js5
-rw-r--r--share/www/script/couch_test_runner.js15
-rw-r--r--src/couchdb/priv/Makefile.am11
-rw-r--r--src/couchdb/priv/couch_js/http.c318
-rw-r--r--src/couchdb/priv/couch_js/http.h10
-rw-r--r--src/couchdb/priv/couch_js/main.c327
-rw-r--r--src/couchdb/priv/couch_js/utf8.c9
9 files changed, 555 insertions, 183 deletions
diff --git a/configure.ac b/configure.ac
index 5124b8b1..907fc6a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -109,15 +109,13 @@ esac
AM_CONDITIONAL([WINDOWS], [test x$IS_WINDOWS = xTRUE])
-AC_CHECK_LIB([mozjs185], [JS_NewContext], [JS_LIB_BASE=mozjs185], [
- AC_CHECK_LIB([mozjs185-1.0], [JS_NewContext], [JS_LIB_BASE=mozjs185-1.0], [
- AC_CHECK_LIB([mozjs], [JS_NewContext], [JS_LIB_BASE=mozjs], [
- AC_CHECK_LIB([js], [JS_NewContext], [JS_LIB_BASE=js], [
- AC_CHECK_LIB([js3250], [JS_NewContext], [JS_LIB_BASE=js3250], [
- AC_CHECK_LIB([js32], [JS_NewContext], [JS_LIB_BASE=js32], [
- AC_MSG_ERROR([Could not find the js library.
+AC_CHECK_LIB([mozjs], [JS_NewContext], [JS_LIB_BASE=mozjs], [
+ AC_CHECK_LIB([js], [JS_NewContext], [JS_LIB_BASE=js], [
+ AC_CHECK_LIB([js3250], [JS_NewContext], [JS_LIB_BASE=js3250], [
+ AC_CHECK_LIB([js32], [JS_NewContext], [JS_LIB_BASE=js32], [
+ AC_MSG_ERROR([Could not find the js library.
-Is the Mozilla SpiderMonkey library installed?])])])])])])])
+Is the Mozilla SpiderMonkey library installed?])])])])])
AC_SUBST(JS_LIB_BASE)
@@ -180,19 +178,16 @@ Are the Mozilla SpiderMonkey headers installed?])
AC_SUBST(JSLIB)
AC_LANG_PUSH(C)
-
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_NewCompartmentAndGlobalObject],
- AC_DEFINE([SM185], [1],
- [Use SpiderMonkey 1.8.5]))
-
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_ThrowStopIteration],
- AC_DEFINE([SM180], [1],
- [Use SpiderMonkey 1.8.0]))
-
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_GetStringCharsAndLength],
- AC_DEFINE([HAVE_JS_GET_STRING_CHARS_AND_LENGTH], [1],
- [Use newer JS_GetCharsAndLength function.]))
-
+OLD_CFLAGS="$CFLAGS"
+CFLAGS="-Werror-implicit-function-declaration"
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <jsapi.h>]],
+ [[JS_SetOperationCallback(0, 0);]]
+ )],
+ AC_DEFINE([USE_JS_SETOPCB], [], [Use new JS_SetOperationCallback])
+)
+CFLAGS="$OLD_CFLAGS"
AC_LANG_POP(C)
AC_ARG_WITH([win32-icu-binaries], [AC_HELP_STRING([--with-win32-icu-binaries=PATH],
@@ -234,10 +229,10 @@ case "$(uname -s)" in
CPPFLAGS="-D_XOPEN_SOURCE $CPPFLAGS"
;;
FreeBSD)
- LIBS="$LIBS -lm -lcrypt"
+ LIBS="$LIBS -lcrypt"
;;
OpenBSD)
- LIBS="$LIBS -lm -lcrypto"
+ LIBS="$LIBS -lcrypto"
;;
esac
diff --git a/share/server/mimeparse.js b/share/server/mimeparse.js
index 42b600fa..3642a194 100644
--- a/share/server/mimeparse.js
+++ b/share/server/mimeparse.js
@@ -97,7 +97,7 @@ var Mimeparse = (function() {
if ((type == targetType || type == "*" || targetType == "*") &&
(subtype == targetSubtype || subtype == "*" || targetSubtype == "*")) {
var matchCount = 0;
- for (var param in targetParams) {
+ for (param in targetParams) {
if (param != 'q' && params[param] && params[param] == targetParams[param]) {
matchCount += 1;
}
diff --git a/share/server/util.js b/share/server/util.js
index f6fa60bb..0b812fe1 100644
--- a/share/server/util.js
+++ b/share/server/util.js
@@ -63,11 +63,6 @@ var Couch = {
},
compileFunction : function(source, ddoc) {
if (!source) throw(["error","not_found","missing function"]);
- // Some newer SpiderMonkey's appear to not like evaluating
- // an anonymous function at global scope. Simple fix just
- // wraps the source with parens so the function object is
- // returned correctly.
- source = "(" + source + ")";
try {
if (sandbox) {
if (ddoc) {
diff --git a/share/www/script/couch_test_runner.js b/share/www/script/couch_test_runner.js
index e14640b6..55a6533f 100644
--- a/share/www/script/couch_test_runner.js
+++ b/share/www/script/couch_test_runner.js
@@ -414,23 +414,10 @@ function waitForSuccess(fun, tag) {
function waitForRestart() {
var waiting = true;
- // Wait for the server to go down but don't
- // wait too long because we might miss the
- // unavailable period.
- var count = 25;
- while (waiting && count > 0) {
- count--;
- try {
- CouchDB.request("GET", "/");
- } catch(e) {
- waiting = false;
- }
- }
- // Wait for it to come back up
- waiting = true;
while (waiting) {
try {
CouchDB.request("GET", "/");
+ CouchDB.request("GET", "/");
waiting = false;
} catch(e) {
// the request will fail until restart completes
diff --git a/src/couchdb/priv/Makefile.am b/src/couchdb/priv/Makefile.am
index b55b5905..ae1b3e38 100644
--- a/src/couchdb/priv/Makefile.am
+++ b/src/couchdb/priv/Makefile.am
@@ -20,10 +20,7 @@ endif
EXTRA_DIST = \
spawnkillable/couchspawnkillable.sh \
- stat_descriptions.cfg.in \
- couch_js/sm170.c \
- couch_js/sm180.c \
- couch_js/sm185.c
+ stat_descriptions.cfg.in
CLEANFILES = $(dist_man1_MANS) stat_descriptions.cfg
@@ -50,14 +47,12 @@ COUCHJS_SRCS = \
couch_js/http.h \
couch_js/main.c \
couch_js/utf8.c \
- couch_js/utf8.h \
- couch_js/util.h \
- couch_js/util.c
+ couch_js/utf8.h
locallibbin_PROGRAMS = couchjs
couchjs_SOURCES = $(COUCHJS_SRCS)
couchjs_LDFLAGS = $(CURL_LDFLAGS)
-couchjs_CFLAGS = -g -Wall -Werror -D_BSD_SOURCE $(CURL_CFLAGS)
+couchjs_CFLAGS = -D_BSD_SOURCE $(CURL_CFLAGS)
couchjs_LDADD = $(CURL_LDFLAGS) @JSLIB@
couchpriv_DATA = stat_descriptions.cfg
diff --git a/src/couchdb/priv/couch_js/http.c b/src/couchdb/priv/couch_js/http.c
index 77078e35..6c2a8a82 100644
--- a/src/couchdb/priv/couch_js/http.c
+++ b/src/couchdb/priv/couch_js/http.c
@@ -14,31 +14,19 @@
#include <stdlib.h>
#include <string.h>
#include <jsapi.h>
-#include "config.h"
-#include "utf8.h"
-
-
#include <curl/curl.h>
+#include "utf8.h"
-void
-http_check_enabled()
-{
- return;
-}
-
-
-// Map some of the string function names to things which exist on Windows
#ifdef XP_WIN
+// Map some of the string function names to things which exist on Windows
#define strcasecmp _strcmpi
#define strncasecmp _strnicmp
#define snprintf _snprintf
#endif
-
typedef struct curl_slist CurlHeaders;
-
typedef struct {
int method;
char* url;
@@ -46,10 +34,8 @@ typedef struct {
jsint last_status;
} HTTPData;
-
char* METHODS[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "COPY", NULL};
-
#define GET 0
#define HEAD 1
#define POST 2
@@ -57,17 +43,14 @@ char* METHODS[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "COPY", NULL};
#define DELETE 4
#define COPY 5
-
static JSBool
go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t blen);
-
static JSString*
str_from_binary(JSContext* cx, char* data, size_t length);
-
-JSBool
-http_ctor(JSContext* cx, JSObject* req)
+static JSBool
+constructor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
{
HTTPData* http = NULL;
JSBool ret = JS_FALSE;
@@ -84,12 +67,12 @@ http_ctor(JSContext* cx, JSObject* req)
http->req_headers = NULL;
http->last_status = -1;
- if(!JS_SetPrivate(cx, req, http))
+ if(!JS_SetPrivate(cx, obj, http))
{
JS_ReportError(cx, "Failed to set private CouchHTTP data.");
goto error;
}
-
+
ret = JS_TRUE;
goto success;
@@ -100,76 +83,90 @@ success:
return ret;
}
-
-void
-http_dtor(JSContext* cx, JSObject* obj)
+static void
+destructor(JSContext* cx, JSObject* obj)
{
HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
- if(http) {
+ if(!http)
+ {
+ fprintf(stderr, "Unable to destroy invalid CouchHTTP instance.\n");
+ }
+ else
+ {
if(http->url) free(http->url);
if(http->req_headers) curl_slist_free_all(http->req_headers);
free(http);
}
}
-
-JSBool
-http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc)
-{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
+static JSBool
+open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
char* method = NULL;
- int methid;
+ char* url = NULL;
JSBool ret = JS_FALSE;
+ int methid;
- if(!http) {
+ if(!http)
+ {
JS_ReportError(cx, "Invalid CouchHTTP instance.");
goto done;
}
- if(mth == JSVAL_VOID) {
+ if(argv[0] == JSVAL_VOID)
+ {
JS_ReportError(cx, "You must specify a method.");
goto done;
}
- method = enc_string(cx, mth, NULL);
- if(!method) {
+ method = enc_string(cx, argv[0], NULL);
+ if(!method)
+ {
JS_ReportError(cx, "Failed to encode method.");
goto done;
}
- for(methid = 0; METHODS[methid] != NULL; methid++) {
+ for(methid = 0; METHODS[methid] != NULL; methid++)
+ {
if(strcasecmp(METHODS[methid], method) == 0) break;
}
- if(methid > COPY) {
+ if(methid > COPY)
+ {
JS_ReportError(cx, "Invalid method specified.");
goto done;
}
http->method = methid;
- if(url == JSVAL_VOID) {
+ if(argv[1] == JSVAL_VOID)
+ {
JS_ReportError(cx, "You must specify a URL.");
goto done;
}
- if(http->url != NULL) {
+ if(http->url)
+ {
free(http->url);
http->url = NULL;
}
- http->url = enc_string(cx, url, NULL);
- if(http->url == NULL) {
+ http->url = enc_string(cx, argv[1], NULL);
+ if(!http->url)
+ {
JS_ReportError(cx, "Failed to encode URL.");
goto done;
}
- if(snc != JSVAL_FALSE) {
- JS_ReportError(cx, "Synchronous flag must be false.");
+ if(argv[2] != JSVAL_VOID && argv[2] != JSVAL_FALSE)
+ {
+ JS_ReportError(cx, "Synchronous flag must be false if specified.");
goto done;
}
- if(http->req_headers) {
+ if(http->req_headers)
+ {
curl_slist_free_all(http->req_headers);
http->req_headers = NULL;
}
@@ -184,42 +181,42 @@ done:
return ret;
}
-
-JSBool
-http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val)
-{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
+static JSBool
+setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
char* keystr = NULL;
char* valstr = NULL;
char* hdrbuf = NULL;
size_t hdrlen = -1;
JSBool ret = JS_FALSE;
- if(!http) {
+ if(!http)
+ {
JS_ReportError(cx, "Invalid CouchHTTP instance.");
goto done;
}
- if(name == JSVAL_VOID)
+ if(argv[0] == JSVAL_VOID)
{
JS_ReportError(cx, "You must speciy a header name.");
goto done;
}
- keystr = enc_string(cx, name, NULL);
+ keystr = enc_string(cx, argv[0], NULL);
if(!keystr)
{
JS_ReportError(cx, "Failed to encode header name.");
goto done;
}
- if(val == JSVAL_VOID)
+ if(argv[1] == JSVAL_VOID)
{
JS_ReportError(cx, "You must specify a header value.");
goto done;
}
- valstr = enc_string(cx, val, NULL);
+ valstr = enc_string(cx, argv[1], NULL);
if(!valstr)
{
JS_ReportError(cx, "Failed to encode header value.");
@@ -228,7 +225,8 @@ http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val)
hdrlen = strlen(keystr) + strlen(valstr) + 3;
hdrbuf = (char*) malloc(hdrlen * sizeof(char));
- if(!hdrbuf) {
+ if(!hdrbuf)
+ {
JS_ReportError(cx, "Failed to allocate header buffer.");
goto done;
}
@@ -242,50 +240,121 @@ done:
if(keystr) free(keystr);
if(valstr) free(valstr);
if(hdrbuf) free(hdrbuf);
+
return ret;
}
-JSBool
-http_send(JSContext* cx, JSObject* req, jsval body)
+static JSBool
+sendreq(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
- char* bodystr = NULL;
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
+ char* body = NULL;
size_t bodylen = 0;
JSBool ret = JS_FALSE;
- if(!http) {
+ if(!http)
+ {
JS_ReportError(cx, "Invalid CouchHTTP instance.");
goto done;
}
- if(body != JSVAL_VOID && body != JS_GetEmptyStringValue(cx)) {
- bodystr = enc_string(cx, body, &bodylen);
- if(!bodystr) {
+ if(argv[0] != JSVAL_VOID && argv[0] != JS_GetEmptyStringValue(cx))
+ {
+ body = enc_string(cx, argv[0], &bodylen);
+ if(!body)
+ {
JS_ReportError(cx, "Failed to encode body.");
goto done;
}
}
- ret = go(cx, req, http, bodystr, bodylen);
+ ret = go(cx, obj, http, body, bodylen);
done:
- if(bodystr) free(bodystr);
+ if(body) free(body);
return ret;
}
-int
-http_status(JSContext* cx, JSObject* req)
+static JSBool
+status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
- if(!http) {
+ if(!http)
+ {
JS_ReportError(cx, "Invalid CouchHTTP instance.");
return JS_FALSE;
}
+
+ if(INT_FITS_IN_JSVAL(http->last_status))
+ {
+ *vp = INT_TO_JSVAL(http->last_status);
+ return JS_TRUE;
+ }
+ else
+ {
+ JS_ReportError(cx, "INTERNAL: Invalid last_status");
+ return JS_FALSE;
+ }
+}
+
+JSClass CouchHTTPClass = {
+ "CouchHTTP",
+ JSCLASS_HAS_PRIVATE
+ | JSCLASS_CONSTRUCT_PROTOTYPE
+ | JSCLASS_HAS_RESERVED_SLOTS(2),
+ JS_PropertyStub,
+ JS_PropertyStub,
+ JS_PropertyStub,
+ JS_PropertyStub,
+ JS_EnumerateStub,
+ JS_ResolveStub,
+ JS_ConvertStub,
+ destructor,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+JSPropertySpec CouchHTTPProperties[] = {
+ {"status", 0, JSPROP_READONLY, status, NULL},
+ {0, 0, 0, 0, 0}
+};
+
+JSFunctionSpec CouchHTTPFunctions[] = {
+ {"_open", open, 3, 0, 0},
+ {"_setRequestHeader", setheader, 2, 0, 0},
+ {"_send", sendreq, 1, 0, 0},
+ {0, 0, 0, 0, 0}
+};
+
+JSObject*
+install_http(JSContext* cx, JSObject* glbl)
+{
+ JSObject* klass = NULL;
+ HTTPData* http = NULL;
- return http->last_status;
+ klass = JS_InitClass(
+ cx,
+ glbl,
+ NULL,
+ &CouchHTTPClass,
+ constructor,
+ 0,
+ CouchHTTPProperties,
+ CouchHTTPFunctions,
+ NULL,
+ NULL
+ );
+
+ if(!klass)
+ {
+ fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
+ return NULL;
+ }
+
+ return klass;
}
+
// Curl Helpers
typedef struct {
@@ -295,7 +364,6 @@ typedef struct {
char* sendbuf;
size_t sendlen;
size_t sent;
- int sent_once;
char* recvbuf;
size_t recvlen;
size_t read;
@@ -327,13 +395,13 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
state.sendbuf = body;
state.sendlen = bodylen;
state.sent = 0;
- state.sent_once = 0;
state.recvbuf = NULL;
state.recvlen = 0;
state.read = 0;
- if(HTTP_HANDLE == NULL) {
+ if(HTTP_HANDLE == NULL)
+ {
HTTP_HANDLE = curl_easy_init();
curl_easy_setopt(HTTP_HANDLE, CURLOPT_READFUNCTION, send_body);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKFUNCTION,
@@ -348,12 +416,14 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
"CouchHTTP Client - Relax");
}
- if(!HTTP_HANDLE) {
+ if(!HTTP_HANDLE)
+ {
JS_ReportError(cx, "Failed to initialize cURL handle.");
goto done;
}
- if(http->method < 0 || http->method > COPY) {
+ if(http->method < 0 || http->method > COPY)
+ {
JS_ReportError(cx, "INTERNAL: Unknown method.");
goto done;
}
@@ -363,21 +433,27 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 0);
- if(http->method == HEAD) {
+ if(http->method == HEAD)
+ {
curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOBODY, 1);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0);
- } else if(http->method == POST || http->method == PUT) {
+ }
+ else if(http->method == POST || http->method == PUT)
+ {
curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 1);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0);
}
- if(body && bodylen) {
+ if(body && bodylen)
+ {
curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, bodylen);
- } else {
+ }
+ else
+ {
curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, 0);
}
- // curl_easy_setopt(HTTP_HANDLE, CURLOPT_VERBOSE, 1);
+ //curl_easy_setopt(HTTP_HANDLE, CURLOPT_VERBOSE, 1);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_URL, http->url);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_HTTPHEADER, http->req_headers);
@@ -386,32 +462,39 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEHEADER, &state);
curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEDATA, &state);
- if(curl_easy_perform(HTTP_HANDLE) != 0) {
+ if(curl_easy_perform(HTTP_HANDLE) != 0)
+ {
JS_ReportError(cx, "Failed to execute HTTP request: %s", ERRBUF);
goto done;
}
- if(!state.resp_headers) {
+ if(!state.resp_headers)
+ {
JS_ReportError(cx, "Failed to recieve HTTP headers.");
goto done;
}
tmp = OBJECT_TO_JSVAL(state.resp_headers);
if(!JS_DefineProperty(
- cx, obj,
+ cx,
+ obj,
"_headers",
tmp,
- NULL, NULL,
+ NULL,
+ NULL,
JSPROP_READONLY
- )) {
+ ))
+ {
JS_ReportError(cx, "INTERNAL: Failed to set response headers.");
goto done;
}
- if(state.recvbuf) {
+ if(state.recvbuf) // Is good enough?
+ {
state.recvbuf[state.read] = '\0';
jsbody = dec_string(cx, state.recvbuf, state.read+1);
- if(!jsbody) {
+ if(!jsbody)
+ {
// If we can't decode the body as UTF-8 we forcefully
// convert it to a string by just forcing each byte
// to a jschar.
@@ -424,17 +507,22 @@ go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
}
}
tmp = STRING_TO_JSVAL(jsbody);
- } else {
+ }
+ else
+ {
tmp = JS_GetEmptyStringValue(cx);
}
if(!JS_DefineProperty(
- cx, obj,
+ cx,
+ obj,
"responseText",
tmp,
- NULL, NULL,
+ NULL,
+ NULL,
JSPROP_READONLY
- )) {
+ ))
+ {
JS_ReportError(cx, "INTERNAL: Failed to set responseText.");
goto done;
}
@@ -452,20 +540,15 @@ send_body(void *ptr, size_t size, size_t nmem, void *data)
CurlState* state = (CurlState*) data;
size_t length = size * nmem;
size_t towrite = state->sendlen - state->sent;
-
- // Assume this is cURL trying to resend a request that
- // failed.
- if(towrite == 0 && state->sent_once == 0) {
- state->sent_once = 1;
+ if(towrite == 0)
+ {
return 0;
- } else if(towrite == 0) {
- state->sent = 0;
- state->sent_once = 0;
- towrite = state->sendlen;
}
if(length < towrite) towrite = length;
+ //fprintf(stderr, "%lu %lu %lu %lu\n", state->bodyused, state->bodyread, length, towrite);
+
memcpy(ptr, state->sendbuf + state->sent, towrite);
state->sent += towrite;
@@ -489,12 +572,15 @@ recv_header(void *ptr, size_t size, size_t nmem, void *data)
char code[4];
char* header = (char*) ptr;
size_t length = size * nmem;
+ size_t index = 0;
JSString* hdr = NULL;
jsuint hdrlen;
jsval hdrval;
- if(length > 7 && strncasecmp(header, "HTTP/1.", 7) == 0) {
- if(length < 12) {
+ if(length > 7 && strncasecmp(header, "HTTP/1.", 7) == 0)
+ {
+ if(length < 12)
+ {
return CURLE_WRITE_ERROR;
}
@@ -503,7 +589,8 @@ recv_header(void *ptr, size_t size, size_t nmem, void *data)
state->http->last_status = atoi(code);
state->resp_headers = JS_NewArrayObject(state->cx, 0, NULL);
- if(!state->resp_headers) {
+ if(!state->resp_headers)
+ {
return CURLE_WRITE_ERROR;
}
@@ -511,22 +598,26 @@ recv_header(void *ptr, size_t size, size_t nmem, void *data)
}
// We get a notice at the \r\n\r\n after headers.
- if(length <= 2) {
+ if(length <= 2)
+ {
return length;
}
// Append the new header to our array.
hdr = dec_string(state->cx, header, length);
- if(!hdr) {
+ if(!hdr)
+ {
return CURLE_WRITE_ERROR;
}
- if(!JS_GetArrayLength(state->cx, state->resp_headers, &hdrlen)) {
+ if(!JS_GetArrayLength(state->cx, state->resp_headers, &hdrlen))
+ {
return CURLE_WRITE_ERROR;
}
hdrval = STRING_TO_JSVAL(hdr);
- if(!JS_SetElement(state->cx, state->resp_headers, hdrlen, &hdrval)) {
+ if(!JS_SetElement(state->cx, state->resp_headers, hdrlen, &hdrval))
+ {
return CURLE_WRITE_ERROR;
}
@@ -540,13 +631,15 @@ recv_body(void *ptr, size_t size, size_t nmem, void *data)
size_t length = size * nmem;
char* tmp = NULL;
- if(!state->recvbuf) {
+ if(!state->recvbuf)
+ {
state->recvlen = 4096;
state->read = 0;
state->recvbuf = JS_malloc(state->cx, state->recvlen);
}
- if(!state->recvbuf) {
+ if(!state->recvbuf)
+ {
return CURLE_WRITE_ERROR;
}
@@ -570,7 +663,8 @@ str_from_binary(JSContext* cx, char* data, size_t length)
if(!conv) return NULL;
- for(i = 0; i < length; i++) {
+ for(i = 0; i < length; i++)
+ {
conv[i] = (jschar) data[i];
}
diff --git a/src/couchdb/priv/couch_js/http.h b/src/couchdb/priv/couch_js/http.h
index 373d1e48..b5f8c70f 100644
--- a/src/couchdb/priv/couch_js/http.h
+++ b/src/couchdb/priv/couch_js/http.h
@@ -13,12 +13,6 @@
#ifndef COUCH_JS_HTTP_H
#define COUCH_JS_HTTP_H
-void http_check_enabled();
-JSBool http_ctor(JSContext* cx, JSObject* req);
-void http_dtor(JSContext* cx, JSObject* req);
-JSBool http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc);
-JSBool http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val);
-JSBool http_send(JSContext* cx, JSObject* req, jsval body);
-int http_status(JSContext* cx, JSObject* req);
+JSObject* install_http(JSContext* cx, JSObject* global);
-#endif
+#endif \ No newline at end of file
diff --git a/src/couchdb/priv/couch_js/main.c b/src/couchdb/priv/couch_js/main.c
index 209bb023..376aa15b 100644
--- a/src/couchdb/priv/couch_js/main.c
+++ b/src/couchdb/priv/couch_js/main.c
@@ -10,12 +10,329 @@
// License for the specific language governing permissions and limitations under
// the License.
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <jsapi.h>
#include "config.h"
-#if defined(SM185)
-#include "sm185.c"
-#elif defined(SM180)
-#include "sm180.c"
+#include "utf8.h"
+#include "http.h"
+
+int gExitCode = 0;
+
+#ifdef JS_THREADSAFE
+#define SETUP_REQUEST(cx) \
+ JS_SetContextThread(cx); \
+ JS_BeginRequest(cx);
+#define FINISH_REQUEST(cx) \
+ JS_EndRequest(cx); \
+ JS_ClearContextThread(cx);
#else
-#include "sm170.c"
+#define SETUP_REQUEST(cx)
+#define FINISH_REQUEST(cx)
#endif
+
+static JSBool
+evalcx(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *str;
+ JSObject *sandbox;
+ JSContext *subcx;
+ const jschar *src;
+ size_t srclen;
+ JSBool ret = JS_FALSE;
+ jsval v;
+
+ sandbox = NULL;
+ if(!JS_ConvertArguments(cx, argc, argv, "S / o", &str, &sandbox))
+ {
+ return JS_FALSE;
+ }
+
+ subcx = JS_NewContext(JS_GetRuntime(cx), 8L * 1024L);
+ if(!subcx)
+ {
+ JS_ReportOutOfMemory(cx);
+ return JS_FALSE;
+ }
+
+ SETUP_REQUEST(subcx);
+
+ src = JS_GetStringChars(str);
+ srclen = JS_GetStringLength(str);
+
+ if(!sandbox)
+ {
+ sandbox = JS_NewObject(subcx, NULL, NULL, NULL);
+ if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) goto done;
+ }
+
+ if(srclen == 0)
+ {
+ *rval = OBJECT_TO_JSVAL(sandbox);
+ }
+ else
+ {
+ JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, rval);
+ }
+
+ ret = JS_TRUE;
+
+done:
+ FINISH_REQUEST(subcx);
+ JS_DestroyContext(subcx);
+ return ret;
+}
+
+static JSBool
+gc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JS_GC(cx);
+ return JS_TRUE;
+}
+
+static JSBool
+print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ uintN i;
+ char *bytes;
+
+ for(i = 0; i < argc; i++)
+ {
+ bytes = enc_string(cx, argv[i], NULL);
+ if(!bytes) return JS_FALSE;
+
+ fprintf(stdout, "%s%s", i ? " " : "", bytes);
+ JS_free(cx, bytes);
+ }
+
+ fputc('\n', stdout);
+ fflush(stdout);
+ return JS_TRUE;
+}
+
+static JSBool
+quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JS_ConvertArguments(cx, argc, argv, "/ i", &gExitCode);
+ return JS_FALSE;
+}
+
+static char*
+readfp(JSContext* cx, FILE* fp, size_t* buflen)
+{
+ char* bytes = NULL;
+ char* tmp = NULL;
+ size_t used = 0;
+ size_t byteslen = 256;
+ size_t readlen = 0;
+
+ bytes = JS_malloc(cx, byteslen);
+ if(bytes == NULL) return NULL;
+
+ while((readlen = js_fgets(bytes+used, byteslen-used, stdin)) > 0)
+ {
+ used += readlen;
+
+ if(bytes[used-1] == '\n')
+ {
+ bytes[used-1] = '\0';
+ break;
+ }
+
+ // Double our buffer and read more.
+ byteslen *= 2;
+ tmp = JS_realloc(cx, bytes, byteslen);
+ if(!tmp)
+ {
+ JS_free(cx, bytes);
+ return NULL;
+ }
+ bytes = tmp;
+ }
+
+ *buflen = used;
+ return bytes;
+}
+
+static JSBool
+readline(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+ jschar *chars;
+ JSString *str;
+ char* bytes;
+ char* tmp;
+ size_t byteslen;
+
+ /* GC Occasionally */
+ JS_MaybeGC(cx);
+
+ bytes = readfp(cx, stdin, &byteslen);
+ if(!bytes) return JS_FALSE;
+
+ /* Treat the empty string specially */
+ if(byteslen == 0)
+ {
+ *rval = JS_GetEmptyStringValue(cx);
+ JS_free(cx, bytes);
+ return JS_TRUE;
+ }
+
+ /* Shrink the buffer to the real size */
+ tmp = JS_realloc(cx, bytes, byteslen);
+ if(!tmp)
+ {
+ JS_free(cx, bytes);
+ return JS_FALSE;
+ }
+ bytes = tmp;
+
+ str = dec_string(cx, bytes, byteslen);
+ JS_free(cx, bytes);
+
+ if(!str) return JS_FALSE;
+
+ *rval = STRING_TO_JSVAL(str);
+
+ return JS_TRUE;
+}
+
+static JSBool
+seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+ JSObject *target;
+ JSBool deep = JS_FALSE;
+
+ if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
+ return JS_FALSE;
+ if (!target)
+ return JS_TRUE;
+ return JS_SealObject(cx, target, deep);
+}
+
+static void
+execute_script(JSContext *cx, JSObject *obj, const char *filename) {
+ FILE *file;
+ JSScript *script;
+ jsval result;
+
+ if(!filename || strcmp(filename, "-") == 0)
+ {
+ file = stdin;
+ }
+ else
+ {
+ file = fopen(filename, "r");
+ if (!file)
+ {
+ fprintf(stderr, "could not open script file %s\n", filename);
+ gExitCode = 1;
+ return;
+ }
+ }
+
+ script = JS_CompileFileHandle(cx, obj, filename, file);
+ if(script)
+ {
+ JS_ExecuteScript(cx, obj, script, &result);
+ JS_DestroyScript(cx, script);
+ }
+}
+
+static void
+printerror(JSContext *cx, const char *mesg, JSErrorReport *report)
+{
+ if(!report || !JSREPORT_IS_WARNING(report->flags))
+ {
+ fprintf(stderr, "%s\n", mesg);
+ }
+}
+
+static JSFunctionSpec global_functions[] = {
+ {"evalcx", evalcx, 0, 0, 0},
+ {"gc", gc, 0, 0, 0},
+ {"print", print, 0, 0, 0},
+ {"quit", quit, 0, 0, 0},
+ {"readline", readline, 0, 0, 0},
+ {"seal", seal, 0, 0, 0},
+ {0, 0, 0, 0, 0}
+};
+
+static JSClass global_class = {
+ "GlobalClass",
+ JSCLASS_GLOBAL_FLAGS,
+ JS_PropertyStub,
+ JS_PropertyStub,
+ JS_PropertyStub,
+ JS_PropertyStub,
+ JS_EnumerateStub,
+ JS_ResolveStub,
+ JS_ConvertStub,
+ JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+int
+main(int argc, const char * argv[])
+{
+ JSRuntime* rt = NULL;
+ JSContext* cx = NULL;
+ JSObject* global = NULL;
+ JSFunctionSpec* sp = NULL;
+ int i = 0;
+
+ rt = JS_NewRuntime(64L * 1024L * 1024L);
+ if (!rt) return 1;
+
+ cx = JS_NewContext(rt, 8L * 1024L);
+ if (!cx) return 1;
+
+ JS_SetErrorReporter(cx, printerror);
+ JS_ToggleOptions(cx, JSOPTION_XML);
+
+ SETUP_REQUEST(cx);
+
+ global = JS_NewObject(cx, &global_class, NULL, NULL);
+ if (!global) return 1;
+ if (!JS_InitStandardClasses(cx, global)) return 1;
+
+ for(sp = global_functions; sp->name != NULL; sp++)
+ {
+ if(!JS_DefineFunction(cx, global,
+ sp->name, sp->call, sp->nargs, sp->flags))
+ {
+ fprintf(stderr, "Failed to create function: %s\n", sp->name);
+ return 1;
+ }
+ }
+
+ if(!install_http(cx, global))
+ {
+ return 1;
+ }
+
+ JS_SetGlobalObject(cx, global);
+
+ if(argc > 2)
+ {
+ fprintf(stderr, "incorrect number of arguments\n\n");
+ fprintf(stderr, "usage: %s <scriptfile>\n", argv[0]);
+ return 2;
+ }
+
+ if(argc == 0)
+ {
+ execute_script(cx, global, NULL);
+ }
+ else
+ {
+ execute_script(cx, global, argv[1]);
+ }
+
+ FINISH_REQUEST(cx);
+
+ JS_DestroyContext(cx);
+ JS_DestroyRuntime(rt);
+ JS_ShutDown();
+
+ return gExitCode;
+}
diff --git a/src/couchdb/priv/couch_js/utf8.c b/src/couchdb/priv/couch_js/utf8.c
index d6064267..699a6fee 100644
--- a/src/couchdb/priv/couch_js/utf8.c
+++ b/src/couchdb/priv/couch_js/utf8.c
@@ -11,7 +11,6 @@
// the License.
#include <jsapi.h>
-#include "config.h"
static int
enc_char(uint8 *utf8Buffer, uint32 ucs4Char)
@@ -122,7 +121,7 @@ char*
enc_string(JSContext* cx, jsval arg, size_t* buflen)
{
JSString* str = NULL;
- const jschar* src = NULL;
+ jschar* src = NULL;
char* bytes = NULL;
size_t srclen = 0;
size_t byteslen = 0;
@@ -130,12 +129,8 @@ enc_string(JSContext* cx, jsval arg, size_t* buflen)
str = JS_ValueToString(cx, arg);
if(!str) goto error;
-#ifdef HAVE_JS_GET_STRING_CHARS_AND_LENGTH
- src = JS_GetStringCharsAndLength(cx, str, &srclen);
-#else
src = JS_GetStringChars(str);
srclen = JS_GetStringLength(str);
-#endif
if(!enc_charbuf(src, srclen, NULL, &byteslen)) goto error;
@@ -288,4 +283,4 @@ error:
success:
return str;
-}
+} \ No newline at end of file