summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Joseph Davis <davisp@apache.org>2011-09-08 05:00:10 +0000
committerPaul Joseph Davis <davisp@apache.org>2011-09-08 05:00:10 +0000
commit71081311b2b11ed923869ce5bd11ce7b0fd1da2c (patch)
tree85c5613959f8435e4b3de922765b01ecb945477d
parent61ca44e384ca10b0b7bf68123c79ed43715ea9c9 (diff)
Fix CouchJS compatibility with older SpiderMonkey.
This is a backport of the work to make CouchJS build against all of the major versions of SpiderMonkey. Thanks to Randall Leeds and Chris Coulson for the original patches. Backport based on r1137464 and r1164346 Fixes COUCHDB-1078 Fixes COUCHDB-1260 git-svn-id: https://svn.apache.org/repos/asf/couchdb/branches/1.1.x@1166525 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--configure.ac41
-rw-r--r--share/server/mimeparse.js2
-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
-rw-r--r--test/javascript/run.tpl2
9 files changed, 179 insertions, 556 deletions
diff --git a/configure.ac b/configure.ac
index 2bdf5aed..5cf37635 100644
--- a/configure.ac
+++ b/configure.ac
@@ -108,13 +108,15 @@ esac
AM_CONDITIONAL([WINDOWS], [test x$IS_WINDOWS = xTRUE])
-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([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.
-Is the Mozilla SpiderMonkey library installed?])])])])])
+Is the Mozilla SpiderMonkey library installed?])])])])])])])
AC_SUBST(JS_LIB_BASE)
@@ -177,16 +179,19 @@ Are the Mozilla SpiderMonkey headers installed?])
AC_SUBST(JSLIB)
AC_LANG_PUSH(C)
-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_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.]))
+
AC_LANG_POP(C)
AC_ARG_WITH([win32-icu-binaries], [AC_HELP_STRING([--with-win32-icu-binaries=PATH],
@@ -228,10 +233,10 @@ case "$(uname -s)" in
CPPFLAGS="-D_XOPEN_SOURCE $CPPFLAGS"
;;
FreeBSD)
- LIBS="$LIBS -lcrypt"
+ LIBS="$LIBS -lm -lcrypt"
;;
OpenBSD)
- LIBS="$LIBS -lcrypto"
+ LIBS="$LIBS -lm -lcrypto"
;;
esac
diff --git a/share/server/mimeparse.js b/share/server/mimeparse.js
index 3642a194..42b600fa 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 (param in targetParams) {
+ for (var param in targetParams) {
if (param != 'q' && params[param] && params[param] == targetParams[param]) {
matchCount += 1;
}
diff --git a/share/www/script/couch_test_runner.js b/share/www/script/couch_test_runner.js
index 55a6533f..e14640b6 100644
--- a/share/www/script/couch_test_runner.js
+++ b/share/www/script/couch_test_runner.js
@@ -414,9 +414,22 @@ function waitForSuccess(fun, tag) {
function waitForRestart() {
var waiting = true;
- while (waiting) {
+ // 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", "/");
waiting = false;
} catch(e) {
diff --git a/src/couchdb/priv/Makefile.am b/src/couchdb/priv/Makefile.am
index b36d828d..3d11e663 100644
--- a/src/couchdb/priv/Makefile.am
+++ b/src/couchdb/priv/Makefile.am
@@ -16,7 +16,10 @@ couchprivlibdir = $(couchlibdir)/priv/lib
EXTRA_DIST = \
spawnkillable/couchspawnkillable.sh \
- stat_descriptions.cfg.in
+ stat_descriptions.cfg.in \
+ couch_js/sm170.c \
+ couch_js/sm180.c \
+ couch_js/sm185.c
CLEANFILES = stat_descriptions.cfg
@@ -42,12 +45,14 @@ COUCHJS_SRCS = \
couch_js/http.h \
couch_js/main.c \
couch_js/utf8.c \
- couch_js/utf8.h
+ couch_js/utf8.h \
+ couch_js/util.h \
+ couch_js/util.c
locallibbin_PROGRAMS = couchjs
couchjs_SOURCES = $(COUCHJS_SRCS)
couchjs_LDFLAGS = $(CURL_LDFLAGS)
-couchjs_CFLAGS = -D_BSD_SOURCE $(CURL_CFLAGS)
+couchjs_CFLAGS = -g -Wall -Werror -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 6c2a8a82..77078e35 100644
--- a/src/couchdb/priv/couch_js/http.c
+++ b/src/couchdb/priv/couch_js/http.c
@@ -14,19 +14,31 @@
#include <stdlib.h>
#include <string.h>
#include <jsapi.h>
+#include "config.h"
+#include "utf8.h"
+
+
#include <curl/curl.h>
-#include "utf8.h"
-#ifdef XP_WIN
+void
+http_check_enabled()
+{
+ return;
+}
+
+
// Map some of the string function names to things which exist on Windows
+#ifdef XP_WIN
#define strcasecmp _strcmpi
#define strncasecmp _strnicmp
#define snprintf _snprintf
#endif
+
typedef struct curl_slist CurlHeaders;
+
typedef struct {
int method;
char* url;
@@ -34,8 +46,10 @@ typedef struct {
jsint last_status;
} HTTPData;
+
char* METHODS[] = {"GET", "HEAD", "POST", "PUT", "DELETE", "COPY", NULL};
+
#define GET 0
#define HEAD 1
#define POST 2
@@ -43,14 +57,17 @@ 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);
-static JSBool
-constructor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+
+JSBool
+http_ctor(JSContext* cx, JSObject* req)
{
HTTPData* http = NULL;
JSBool ret = JS_FALSE;
@@ -67,12 +84,12 @@ constructor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
http->req_headers = NULL;
http->last_status = -1;
- if(!JS_SetPrivate(cx, obj, http))
+ if(!JS_SetPrivate(cx, req, http))
{
JS_ReportError(cx, "Failed to set private CouchHTTP data.");
goto error;
}
-
+
ret = JS_TRUE;
goto success;
@@ -83,90 +100,76 @@ success:
return ret;
}
-static void
-destructor(JSContext* cx, JSObject* obj)
+
+void
+http_dtor(JSContext* cx, JSObject* obj)
{
HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
- if(!http)
- {
- fprintf(stderr, "Unable to destroy invalid CouchHTTP instance.\n");
- }
- else
- {
+ if(http) {
if(http->url) free(http->url);
if(http->req_headers) curl_slist_free_all(http->req_headers);
free(http);
}
}
-static JSBool
-open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
-{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
+
+JSBool
+http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc)
+{
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
char* method = NULL;
- char* url = NULL;
- JSBool ret = JS_FALSE;
int methid;
+ JSBool ret = JS_FALSE;
- if(!http)
- {
+ if(!http) {
JS_ReportError(cx, "Invalid CouchHTTP instance.");
goto done;
}
- if(argv[0] == JSVAL_VOID)
- {
+ if(mth == JSVAL_VOID) {
JS_ReportError(cx, "You must specify a method.");
goto done;
}
- method = enc_string(cx, argv[0], NULL);
- if(!method)
- {
+ method = enc_string(cx, mth, 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(argv[1] == JSVAL_VOID)
- {
+ if(url == JSVAL_VOID) {
JS_ReportError(cx, "You must specify a URL.");
goto done;
}
- if(http->url)
- {
+ if(http->url != NULL) {
free(http->url);
http->url = NULL;
}
- http->url = enc_string(cx, argv[1], NULL);
- if(!http->url)
- {
+ http->url = enc_string(cx, url, NULL);
+ if(http->url == NULL) {
JS_ReportError(cx, "Failed to encode URL.");
goto done;
}
- if(argv[2] != JSVAL_VOID && argv[2] != JSVAL_FALSE)
- {
- JS_ReportError(cx, "Synchronous flag must be false if specified.");
+ if(snc != JSVAL_FALSE) {
+ JS_ReportError(cx, "Synchronous flag must be false.");
goto done;
}
- if(http->req_headers)
- {
+ if(http->req_headers) {
curl_slist_free_all(http->req_headers);
http->req_headers = NULL;
}
@@ -181,42 +184,42 @@ done:
return ret;
}
-static JSBool
-setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
-{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
+
+JSBool
+http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val)
+{
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
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(argv[0] == JSVAL_VOID)
+ if(name == JSVAL_VOID)
{
JS_ReportError(cx, "You must speciy a header name.");
goto done;
}
- keystr = enc_string(cx, argv[0], NULL);
+ keystr = enc_string(cx, name, NULL);
if(!keystr)
{
JS_ReportError(cx, "Failed to encode header name.");
goto done;
}
- if(argv[1] == JSVAL_VOID)
+ if(val == JSVAL_VOID)
{
JS_ReportError(cx, "You must specify a header value.");
goto done;
}
- valstr = enc_string(cx, argv[1], NULL);
+ valstr = enc_string(cx, val, NULL);
if(!valstr)
{
JS_ReportError(cx, "Failed to encode header value.");
@@ -225,8 +228,7 @@ setheader(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
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;
}
@@ -240,121 +242,50 @@ done:
if(keystr) free(keystr);
if(valstr) free(valstr);
if(hdrbuf) free(hdrbuf);
-
return ret;
}
-static JSBool
-sendreq(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+JSBool
+http_send(JSContext* cx, JSObject* req, jsval body)
{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
- char* body = NULL;
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
+ char* bodystr = NULL;
size_t bodylen = 0;
JSBool ret = JS_FALSE;
- if(!http)
- {
+ if(!http) {
JS_ReportError(cx, "Invalid CouchHTTP instance.");
goto done;
}
- if(argv[0] != JSVAL_VOID && argv[0] != JS_GetEmptyStringValue(cx))
- {
- body = enc_string(cx, argv[0], &bodylen);
- if(!body)
- {
+ if(body != JSVAL_VOID && body != JS_GetEmptyStringValue(cx)) {
+ bodystr = enc_string(cx, body, &bodylen);
+ if(!bodystr) {
JS_ReportError(cx, "Failed to encode body.");
goto done;
}
}
- ret = go(cx, obj, http, body, bodylen);
+ ret = go(cx, req, http, bodystr, bodylen);
done:
- if(body) free(body);
+ if(bodystr) free(bodystr);
return ret;
}
-static JSBool
-status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
+int
+http_status(JSContext* cx, JSObject* req)
{
- HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
+ HTTPData* http = (HTTPData*) JS_GetPrivate(cx, req);
- 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;
- 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;
+ return http->last_status;
}
-
// Curl Helpers
typedef struct {
@@ -364,6 +295,7 @@ typedef struct {
char* sendbuf;
size_t sendlen;
size_t sent;
+ int sent_once;
char* recvbuf;
size_t recvlen;
size_t read;
@@ -395,13 +327,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,
@@ -416,14 +348,12 @@ 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;
}
@@ -433,27 +363,21 @@ 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);
@@ -462,39 +386,32 @@ 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) // Is good enough?
- {
+ if(state.recvbuf) {
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.
@@ -507,22 +424,17 @@ 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;
}
@@ -540,15 +452,20 @@ 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;
- if(towrite == 0)
- {
+
+ // Assume this is cURL trying to resend a request that
+ // failed.
+ if(towrite == 0 && state->sent_once == 0) {
+ state->sent_once = 1;
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;
@@ -572,15 +489,12 @@ 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;
}
@@ -589,8 +503,7 @@ 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;
}
@@ -598,26 +511,22 @@ 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;
}
@@ -631,15 +540,13 @@ 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;
}
@@ -663,8 +570,7 @@ 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 b5f8c70f..373d1e48 100644
--- a/src/couchdb/priv/couch_js/http.h
+++ b/src/couchdb/priv/couch_js/http.h
@@ -13,6 +13,12 @@
#ifndef COUCH_JS_HTTP_H
#define COUCH_JS_HTTP_H
-JSObject* install_http(JSContext* cx, JSObject* global);
+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);
-#endif \ No newline at end of file
+#endif
diff --git a/src/couchdb/priv/couch_js/main.c b/src/couchdb/priv/couch_js/main.c
index 376aa15b..209bb023 100644
--- a/src/couchdb/priv/couch_js/main.c
+++ b/src/couchdb/priv/couch_js/main.c
@@ -10,329 +10,12 @@
// 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"
-#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);
+#if defined(SM185)
+#include "sm185.c"
+#elif defined(SM180)
+#include "sm180.c"
#else
-#define SETUP_REQUEST(cx)
-#define FINISH_REQUEST(cx)
+#include "sm170.c"
#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 699a6fee..d6064267 100644
--- a/src/couchdb/priv/couch_js/utf8.c
+++ b/src/couchdb/priv/couch_js/utf8.c
@@ -11,6 +11,7 @@
// the License.
#include <jsapi.h>
+#include "config.h"
static int
enc_char(uint8 *utf8Buffer, uint32 ucs4Char)
@@ -121,7 +122,7 @@ char*
enc_string(JSContext* cx, jsval arg, size_t* buflen)
{
JSString* str = NULL;
- jschar* src = NULL;
+ const jschar* src = NULL;
char* bytes = NULL;
size_t srclen = 0;
size_t byteslen = 0;
@@ -129,8 +130,12 @@ 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;
@@ -283,4 +288,4 @@ error:
success:
return str;
-} \ No newline at end of file
+}
diff --git a/test/javascript/run.tpl b/test/javascript/run.tpl
index c5abe6e7..1389a4f9 100644
--- a/test/javascript/run.tpl
+++ b/test/javascript/run.tpl
@@ -27,4 +27,4 @@ cat $SCRIPT_DIR/json2.js \
$SCRIPT_DIR/test/*.js \
$JS_TEST_DIR/couch_http.js \
$JS_TEST_DIR/cli_runner.js \
- | $COUCHJS -
+ | $COUCHJS --http -