couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dav...@apache.org
Subject svn commit: r1164346 - in /couchdb/trunk: ./ share/server/ share/www/script/ src/couchdb/priv/ src/couchdb/priv/couch_js/ test/javascript/
Date Fri, 02 Sep 2011 04:03:06 GMT
Author: davisp
Date: Fri Sep  2 04:03:05 2011
New Revision: 1164346

URL: http://svn.apache.org/viewvc?rev=1164346&view=rev
Log:
Fix CouchJS compatibility with older Spidermonkey.

The recent patch to enable support for SM 1.8.5 broke support for
1.7.0. This patch updates couchjs to work with all of the major
variants of Spidermonkey.

Versions tested:

    1.7.0
    1.8.0rc1
    1.8.5
    1.9.2.something (XULRunner)

Various combinations have been tested on OS X, Ubuntu, FreeBSD and
Windows.

Fixes COUCHDB-1260


Added:
    couchdb/trunk/src/couchdb/priv/couch_js/sm170.c
    couchdb/trunk/src/couchdb/priv/couch_js/sm180.c
    couchdb/trunk/src/couchdb/priv/couch_js/sm185.c
    couchdb/trunk/src/couchdb/priv/couch_js/util.c
    couchdb/trunk/src/couchdb/priv/couch_js/util.h
Modified:
    couchdb/trunk/configure.ac
    couchdb/trunk/share/server/loop.js
    couchdb/trunk/share/server/mimeparse.js
    couchdb/trunk/share/server/util.js
    couchdb/trunk/share/www/script/couch_test_runner.js
    couchdb/trunk/src/couchdb/priv/Makefile.am
    couchdb/trunk/src/couchdb/priv/couch_js/http.c
    couchdb/trunk/src/couchdb/priv/couch_js/http.h
    couchdb/trunk/src/couchdb/priv/couch_js/jscompat.h
    couchdb/trunk/src/couchdb/priv/couch_js/main.c
    couchdb/trunk/test/javascript/run.tpl

Modified: couchdb/trunk/configure.ac
URL: http://svn.apache.org/viewvc/couchdb/trunk/configure.ac?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/configure.ac (original)
+++ couchdb/trunk/configure.ac Fri Sep  2 04:03:05 2011
@@ -185,37 +185,31 @@ AM_CONDITIONAL([WINDOWS], [test x$IS_WIN
 OLD_LIBS="$LIBS"
 LIBS="$JS_LIBS $LIBS"
 AC_CHECK_LIB([mozjs185], [JS_NewContext], [JS_LIB_BASE=mozjs185], [
-    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?])])])])])])
-
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_FreezeObject],
-    AC_DEFINE([HAVE_JS_FREEZE_OBJECT], [1],
-        [Define whether we have JS_FreezeObject]))
-
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_NewGlobalObject],
-    AC_DEFINE([HAVE_JS_NEW_GLOBAL_OBJECT], [1],
-        [Define whether we have JS_NewGlobalObject]))
+    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?])])])])])])])
+
+# Figure out what version of SpiderMonkey to use
+
+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],
-        [Define whether we have JS_GetStringCharsAndLength]))
+        [Use newer JS_GetCharsAndLength function.]))
 
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_NewCompartmentAndGlobalObject],
-    AC_DEFINE([HAVE_COMPARTMENTS], [1],
-        [Define whether we have JS_NewCompartmentAndGlobalObject]))
 
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_StrictPropertyStub],
-    AC_DEFINE([HAVE_JS_STRICT_PROPERTY_STUB], [1],
-        [Define whether we have JS_StrictPropertyStub]))
-
-AC_CHECK_LIB([$JS_LIB_BASE], [JS_DestroyScript],
-    AC_DEFINE([HAVE_SCRIPT_TYPE], [1],
-        [Define whether scripts have a special JSScript type]))
+# Else, hope that 1.7.0 works
 LIBS="$OLD_LIBS"
 
 if test x${IS_WINDOWS} = xTRUE; then
@@ -261,7 +255,7 @@ if test x${IS_WINDOWS} = xTRUE; then
     fi
 fi
 
-JS_LIBS="-l$JS_LIB_BASE $JS_LIBS"
+JS_LIBS="-l$JS_LIB_BASE -lm $JS_LIBS"
 AC_SUBST(JS_LIBS)
 
 OLD_CPPFLAGS="$CPPFLAGS"
@@ -278,38 +272,6 @@ Are the Mozilla SpiderMonkey headers ins
         ])])
 CPPFLAGS="$OLD_CPPFLAGS"
 
-AC_LANG_PUSH(C)
-OLDCFLAGS="$CFLAGS"
-CFLAGS="-Werror-implicit-function-declaration $JS_CFLAGS $OLDCFLAGS"
-AC_COMPILE_IFELSE(
-    [AC_LANG_PROGRAM(
-        [[#include <jsapi.h>]],
-        [[JS_SetOperationCallback(0, 0);]]
-    )],
-    AC_DEFINE([USE_JS_SETOPCB], [], [Use new JS_SetOperationCallback])
-)
-CFLAGS="$JS_CFLAGS $OLDCFLAGS"
-AC_COMPILE_IFELSE(
-    [AC_LANG_PROGRAM(
-        [[#include <jsapi.h>]],
-        [[static JSFunctionSpec fs;
-          fs.extra = 0;]]
-    )],
-    AC_DEFINE([JS_FS_HAS_EXTRA], [1], [JSFunctionSpec has an extra member])
-)
-CFLAGS="$JS_CFLAGS $OLDCFLAGS -Werror"
-AC_COMPILE_IFELSE(
-    [AC_LANG_PROGRAM(
-        [[#include <jsapi.h>
-          static JSBool op(JSContext* cx, JSObject* obj, jsid id, jsval* vp) {}]],
-        [[static JSPropertySpec spec;
-          spec.getter = op;]]
-    )],
-    AC_DEFINE([JS_PROPERTY_OP_HAS_ID_AS_JSID], [1],
-        [The type of "id" in the prototype for JSPropertyOp is a jsid])
-)
-CFLAGS="$OLD_CFLAGS"
-AC_LANG_POP(C)
 
 AC_ARG_WITH([win32-icu-binaries], [AC_HELP_STRING([--with-win32-icu-binaries=PATH],
     [set PATH to the Win32 native ICU binaries directory])], [

Modified: couchdb/trunk/share/server/loop.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/server/loop.js?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/share/server/loop.js (original)
+++ couchdb/trunk/share/server/loop.js Fri Sep  2 04:03:05 2011
@@ -29,7 +29,7 @@ function init_sandbox() {
     sandbox.getRow = Render.getRow;
     sandbox.isArray = isArray;
   } catch (e) {
-    log(e.toSource());
+    //log(e.toSource());
   }
 };
 init_sandbox();

Modified: couchdb/trunk/share/server/mimeparse.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/server/mimeparse.js?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/share/server/mimeparse.js (original)
+++ couchdb/trunk/share/server/mimeparse.js Fri Sep  2 04:03:05 2011
@@ -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;
             }

Modified: couchdb/trunk/share/server/util.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/server/util.js?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/share/server/util.js (original)
+++ couchdb/trunk/share/server/util.js Fri Sep  2 04:03:05 2011
@@ -69,7 +69,7 @@ var Couch = {
       if(typeof CoffeeScript === "undefined") {
         return evalFunction(source, sandbox);
       } else {
-        coffee = CoffeeScript.compile(source, {bare: true});
+        var coffee = CoffeeScript.compile(source, {bare: true});
         return evalFunction(coffee, sandbox);
       }
     }

Modified: couchdb/trunk/share/www/script/couch_test_runner.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch_test_runner.js?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch_test_runner.js (original)
+++ couchdb/trunk/share/www/script/couch_test_runner.js Fri Sep  2 04:03:05 2011
@@ -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
+  // 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) {

Modified: couchdb/trunk/src/couchdb/priv/Makefile.am
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/Makefile.am?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/priv/Makefile.am (original)
+++ couchdb/trunk/src/couchdb/priv/Makefile.am Fri Sep  2 04:03:05 2011
@@ -17,7 +17,10 @@ couchprivlibdir = $(couchlibdir)/priv/li
 EXTRA_DIST = \
 	spawnkillable/couchspawnkillable.sh \
 	stat_descriptions.cfg.in \
-	couch_ejson_compare/erl_nif_compat.h
+	couch_ejson_compare/erl_nif_compat.h \
+	couch_js/sm170.c \
+	couch_js/sm180.c \
+	couch_js/sm185.c
 
 CLEANFILES = stat_descriptions.cfg
 
@@ -44,14 +47,15 @@ endif
 COUCHJS_SRCS = \
 	couch_js/http.c \
 	couch_js/http.h \
-        couch_js/jscompat.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_CFLAGS = -D_BSD_SOURCE $(CURL_CFLAGS) $(JS_CFLAGS)
+couchjs_CFLAGS = -g -Wall -Werror -D_BSD_SOURCE $(CURL_CFLAGS) $(JS_CFLAGS)
 couchjs_LDADD = $(CURL_LIBS) $(JS_LIBS)
 
 couchpriv_DATA = stat_descriptions.cfg

Modified: couchdb/trunk/src/couchdb/priv/couch_js/http.c
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/http.c?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/http.c (original)
+++ couchdb/trunk/src/couchdb/priv/couch_js/http.c Fri Sep  2 04:03:05 2011
@@ -15,35 +15,86 @@
 #include <string.h>
 #include <jsapi.h>
 #include "config.h"
-
-#ifndef HAVE_CURL
+#include "utf8.h"
 
 // Soft dependency on cURL bindings because they're
 // only used when running the JS tests from the
 // command line which is rare.
-JSObject*
-install_http(JSContext* cx, JSObject* glbl)
+#ifndef HAVE_CURL
+
+void
+http_check_enabled()
 {
-    fprintf(stderr, "ERROR: couchjs was not built with cURL support.\n");
-    return NULL;
+    fprintf(stderr, "HTTP API was disabled at compile time.\n");
+    exit(3);
+    return JS_FALSE;
+}
+
+
+JSBool
+http_ctor(JSContext* cx, JSObject* req)
+{
+    return JS_FALSE;
+}
+
+
+JSBool
+http_dtor(JSContext* cx, JSObject* req)
+{
+    return JS_FALSE;
+}
+
+
+JSBool
+http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc)
+{
+    return JS_FALSE;
+}
+
+
+JSBool
+http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val)
+{
+    return JS_FALSE;
+}
+
+
+JSBool
+http_send(JSContext* cx, JSObject* req, jsval body)
+{
+    return JS_FALSE;
+}
+
+
+int
+http_status(JSContext* cx, JSObject* req, jsval body)
+{
+    return -1;
 }
 
-#else
 
+#else
 #include <curl/curl.h>
 
-#include "utf8.h"
-#include "jscompat.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;
@@ -51,8 +102,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
@@ -60,20 +113,21 @@ char* METHODS[] = {"GET", "HEAD", "POST"
 #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);
 
-COUCHJS_CONSTRUCTOR_DECLARE(constructor)
+
+JSBool
+http_ctor(JSContext* cx, JSObject* req)
 {
-    COUCHJS_CONSTRUCTOR_INIT_VARS
     HTTPData* http = NULL;
     JSBool ret = JS_FALSE;
 
-    COUCHJS_CONSTRUCTOR_CONSTRUCT
-
     http = (HTTPData*) malloc(sizeof(HTTPData));
     if(!http)
     {
@@ -86,13 +140,12 @@ COUCHJS_CONSTRUCTOR_DECLARE(constructor)
     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;
     }
 
-    COUCHJS_CONSTRUCTOR_FINISH
     ret = JS_TRUE;
     goto success;
 
@@ -103,94 +156,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)
-    {
-        // mozjs185 seems to create a ghost object that gets finalized
-        // No messing about with flags seems to prevent this or ensure it's
-        // constructed properly.
-        fprintf(stderr, "No valid CouchHTTP instance to destroy [harmless].\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, uintN argc, jsval* vp)
+
+JSBool
+http_open(JSContext* cx, JSObject* req, jsval mth, jsval url, jsval snc)
 {
-    COUCHJS_NATIVE_INIT_VARS(argv, obj)
-    HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
+    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;
     }
@@ -198,7 +233,6 @@ open(JSContext* cx, uintN argc, jsval* v
     // Disable Expect: 100-continue
     http->req_headers = curl_slist_append(http->req_headers, "Expect:");
 
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     ret = JS_TRUE;
 
 done:
@@ -206,43 +240,42 @@ done:
     return ret;
 }
 
-static JSBool
-setheader(JSContext* cx, uintN argc, jsval* vp)
+
+JSBool
+http_set_hdr(JSContext* cx, JSObject* req, jsval name, jsval val)
 {
-    COUCHJS_NATIVE_INIT_VARS(argv, obj)
-    HTTPData* http = (HTTPData*) JS_GetPrivate(cx, obj);
+    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.");
@@ -251,8 +284,7 @@ setheader(JSContext* cx, uintN argc, jsv
     
     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;
     }
@@ -260,137 +292,56 @@ setheader(JSContext* cx, uintN argc, jsv
     snprintf(hdrbuf, hdrlen, "%s: %s", keystr, valstr);
     http->req_headers = curl_slist_append(http->req_headers, hdrbuf);
 
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
     ret = JS_TRUE;
 
 done:
     if(keystr) free(keystr);
     if(valstr) free(valstr);
     if(hdrbuf) free(hdrbuf);
-
     return ret;
 }
 
-static JSBool
-sendreq(JSContext* cx, uintN argc, jsval* vp)
+JSBool
+http_send(JSContext* cx, JSObject* req, jsval body)
 {
-    COUCHJS_NATIVE_INIT_VARS(argv, obj)
-    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);
-    if (ret == JS_TRUE)
-      JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    ret = go(cx, req, http, bodystr, bodylen);
 
 done:
-    if(body) free(body);
+    if(bodystr) free(bodystr);
     return ret;
 }
 
-COUCHJS_GETTER_DECLARE(status)
+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;
     }
 
-#ifndef INT_FITS_IN_JSVAL
-    // jsval's are 64-bits wide in mozjs >= 2.0, so a jsint can use a full
-    // 32-bits now no bits are reserved for tagging
-    *vp = INT_TO_JSVAL(http->last_status);
-    return JS_TRUE;
-#else
-    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;
-    }
-#endif
+    return http->last_status;
 }
 
-JSClass CouchHTTPClass = {
-    "CouchHTTP",
-    JSCLASS_HAS_PRIVATE
-        | JSCLASS_CONSTRUCT_PROTOTYPE
-        | JSCLASS_HAS_RESERVED_SLOTS(2),
-    JS_PropertyStub,
-    JS_PropertyStub,
-    JS_PropertyStub,
-    JS_SETPROPERTY_PROPERTY_STUB,
-    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[] = {
-    JS_FS("_open", COUCHJS_NATIVE_FUNC(open), 3, JSFUN_FAST_NATIVE),
-    JS_FS("_setRequestHeader", COUCHJS_NATIVE_FUNC(setheader), 2, JSFUN_FAST_NATIVE),
-    JS_FS("_send", COUCHJS_NATIVE_FUNC(sendreq), 1, JSFUN_FAST_NATIVE),
-    JS_FS_END
-};
-
-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;
-}
-
-
 // Curl Helpers
 
 typedef struct {
@@ -400,6 +351,7 @@ typedef struct {
     char*       sendbuf;
     size_t      sendlen;
     size_t      sent;
+    int         sent_once;
     char*       recvbuf;
     size_t      recvlen;
     size_t      read;
@@ -431,13 +383,13 @@ go(JSContext* cx, JSObject* obj, HTTPDat
     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,
@@ -452,14 +404,12 @@ go(JSContext* cx, JSObject* obj, HTTPDat
                                             "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;
     }
@@ -469,27 +419,21 @@ go(JSContext* cx, JSObject* obj, HTTPDat
     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);
@@ -498,39 +442,32 @@ go(JSContext* cx, JSObject* obj, HTTPDat
     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.
@@ -543,22 +480,17 @@ go(JSContext* cx, JSObject* obj, HTTPDat
             }
         }
         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;
     }
@@ -576,15 +508,20 @@ send_body(void *ptr, size_t size, size_t
     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;
 
@@ -608,15 +545,12 @@ recv_header(void *ptr, size_t size, size
     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;
         }
 
@@ -625,8 +559,7 @@ recv_header(void *ptr, size_t size, size
         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;
         }
 
@@ -634,26 +567,22 @@ recv_header(void *ptr, size_t size, size
     }
 
     // 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;
     }
 
@@ -667,15 +596,13 @@ recv_body(void *ptr, size_t size, size_t
     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;
     }
 
@@ -699,8 +626,7 @@ str_from_binary(JSContext* cx, char* dat
 
     if(!conv) return NULL;
 
-    for(i = 0; i < length; i++)
-    {
+    for(i = 0; i < length; i++) {
         conv[i] = (jschar) data[i];
     }
 

Modified: couchdb/trunk/src/couchdb/priv/couch_js/http.h
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/http.h?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/http.h (original)
+++ couchdb/trunk/src/couchdb/priv/couch_js/http.h Fri Sep  2 04:03:05 2011
@@ -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

Modified: couchdb/trunk/src/couchdb/priv/couch_js/main.c
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/main.c?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/main.c (original)
+++ couchdb/trunk/src/couchdb/priv/couch_js/main.c Fri Sep  2 04:03:05 2011
@@ -10,437 +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"
-#include "jscompat.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
-#define SETUP_REQUEST(cx)
-#define FINISH_REQUEST(cx)
-#endif
-
-
-static JSClass global_class = {
-    "GlobalClass",
-    JSCLASS_GLOBAL_FLAGS,
-    JS_PropertyStub,
-    JS_PropertyStub,
-    JS_PropertyStub,
-    JS_SETPROPERTY_PROPERTY_STUB,
-    JS_EnumerateStub,
-    JS_ResolveStub,
-    JS_ConvertStub,
-    JS_FinalizeStub,
-    JSCLASS_NO_OPTIONAL_MEMBERS
-};
-
-static JSBool
-evalcx(JSContext* cx, uintN argc, jsval* vp)
-{
-    jsval* argv = JS_ARGV(cx, vp);
-    JSString *str;
-    JSObject *sandbox;
-    JSContext *subcx;
-    const jschar *src;
-    size_t srclen;
-    JSBool ret = JS_FALSE;
-    jsval v;
-#ifdef HAVE_COMPARTMENTS
-    JSCrossCompartmentCall *call = NULL;
-#endif
-
-    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);
-
-#ifdef HAVE_JS_GET_STRING_CHARS_AND_LENGTH
-    src = JS_GetStringCharsAndLength(cx, str, &srclen);
-#else
-    src = JS_GetStringChars(str);
-    srclen = JS_GetStringLength(str);
-#endif
-
-#ifdef HAVE_COMPARTMENTS
-    // Re-use the compartment associated with the main context,
-    // rather than creating a new compartment */
-    JSObject *global = JS_GetGlobalObject(cx);
-    if(!global)
-    {
-       goto done;
-    }
-    call = JS_EnterCrossCompartmentCall(subcx, global);
-#endif
-
-    if(!sandbox)
-    {
-#ifdef HAVE_JS_NEW_GLOBAL_OBJECT
-        sandbox = JS_NewGlobalObject(subcx, &global_class);
+#if defined(SM185)
+#include "sm185.c"
+#elif defined(SM180)
+#include "sm180.c"
 #else
-        sandbox = JS_NewObject(subcx, NULL, NULL, NULL);
+#include "sm170.c"
 #endif
-        if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) goto done;
-    }
-
-    if(srclen == 0)
-    {
-        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sandbox));
-    }
-    else
-    {
-        JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, &JS_RVAL(cx, vp));
-    }
-    
-    ret = JS_TRUE;
-
-done:
-#ifdef HAVE_COMPARTMENTS
-    if(call)
-    {
-        JS_LeaveCrossCompartmentCall(call);
-    }
-#endif
-    FINISH_REQUEST(subcx);
-    JS_DestroyContext(subcx);
-    return ret;
-}
-
-static JSBool
-gc(JSContext* cx, uintN argc, jsval* vp)
-{
-    JS_GC(cx);
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    return JS_TRUE;
-}
-
-static JSBool
-print(JSContext *cx, uintN argc, jsval *vp)
-{
-    jsval *argv = JS_ARGV(cx, vp);
-    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);
-    JS_SET_RVAL(cx, vp, JSVAL_VOID);
-    return JS_TRUE;
-}
-
-static JSBool
-quit(JSContext *cx, uintN argc, jsval *vp)
-{
-    jsval *argv = JS_ARGV(cx, vp);
-    JS_ConvertArguments(cx, argc, argv, "/ i", &gExitCode);
-    return JS_FALSE;
-}
-
-static int
-couchjs_fgets(char *buf, int size, FILE *file)
-{
-    int n, i, c;
-    JSBool crflag;
-
-    n = size - 1;
-    if (n < 0)
-        return -1;
-
-    crflag = JS_FALSE;
-    for (i = 0; i < n && (c = getc(file)) != EOF; i++)
-    {
-        buf[i] = c;
-        if (c == '\n') {        /* any \n ends a line */
-            i++;                /* keep the \n; we know there is room for \0 */
-            break;
-        }
-        if (crflag) {           /* \r not followed by \n ends line at the \r */
-            ungetc(c, file);
-            break;              /* and overwrite c in buf with \0 */
-        }
-        crflag = (c == '\r');
-    }
-
-    buf[i] = '\0';
-    return i;
-}
-
-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 = couchjs_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, uintN argc, jsval *vp) {
-    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)
-    {
-        JS_SET_RVAL(cx, vp, 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;
-
-    JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(str));
-
-    return JS_TRUE;
-}
-
-static JSBool
-seal(JSContext *cx, uintN argc, jsval *vp) {
-    jsval *argv = JS_ARGV(cx, vp);
-    JSObject *target;
-    JSBool deep = JS_FALSE;
-    JSBool ret;
-
-    if (!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
-        return JS_FALSE;
-    if (!target)
-    {
-        JS_SET_RVAL(cx, vp, JSVAL_VOID);
-        return JS_TRUE;
-    }
-
-    COUCHJS_SEAL_OBJECT(ret, cx, target, deep);
-    if (ret == JS_TRUE)
-        JS_SET_RVAL(cx, vp, JSVAL_VOID);
-
-    return ret;
-}
-
-static void
-execute_script(JSContext *cx, JSObject *obj, const char *filename) {
-    FILE *file;
-    COUCHJS_SCRIPT *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);
-        COUCHJS_DESTROY_SCRIPT(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[] = {
-    JS_FS("evalcx", COUCHJS_NATIVE_FUNC(evalcx), 0, JSFUN_FAST_NATIVE),
-    JS_FS("gc", COUCHJS_NATIVE_FUNC(gc), 0, JSFUN_FAST_NATIVE),
-    JS_FS("print", COUCHJS_NATIVE_FUNC(print), 0, JSFUN_FAST_NATIVE),
-    JS_FS("quit", COUCHJS_NATIVE_FUNC(quit), 0, JSFUN_FAST_NATIVE),
-    JS_FS("readline", COUCHJS_NATIVE_FUNC(readline), 0, JSFUN_FAST_NATIVE),
-    JS_FS("seal", COUCHJS_NATIVE_FUNC(seal), 0, JSFUN_FAST_NATIVE),
-    JS_FS_END
-};
-
-int
-usage()
-{
-    fprintf(stderr, "usage: couchjs [-H] [script_name]\n");
-    return 1;
-}
-
-int
-main(int argc, const char * argv[])
-{
-    JSRuntime* rt = NULL;
-    JSContext* cx = NULL;
-    JSObject* global = NULL;
-#ifdef HAVE_COMPARTMENTS
-    JSCrossCompartmentCall *call = NULL;
-#endif
-    JSFunctionSpec* sp = NULL;
-    const char* script_name = NULL;
-    int use_http = 0;
-    int i = 0;
-
-    if(argc > 3)
-    {
-        fprintf(stderr, "ERROR: Too many arguments.\n");
-        return usage();
-    }
-    else if(argc == 3)
-    {
-        if(strcmp(argv[1], "-H"))
-        {
-            fprintf(stderr, "ERROR: Invalid option: %s\n", argv[1]);
-            return usage();
-        }
-        use_http = 1;
-        script_name = argv[2];
-    }
-    else if(argc == 2 && strcmp(argv[1], "-H") == 0)
-    {
-        use_http = 1;
-    }
-    else if (argc == 2)
-    {
-        script_name = argv[1];
-    }
-    // else argc == 1, use defaults
-
-    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);
-
-#ifdef HAVE_COMPARTMENTS
-    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
-    if (!global) return 1;
-    call = JS_EnterCrossCompartmentCall(cx, global);
-#elif HAVE_JS_NEW_GLOBAL_OBJECT
-    global = JS_NewGlobalObject(cx, &global_class);
-    if (!global) return 1;
-#else
-    global = JS_NewObject(cx, &global_class, NULL, NULL);
-    if (!global) return 1;
-    JS_SetGlobalObject(cx, global);
-#endif
-    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(use_http && !install_http(cx, global))
-    {
-        return 2;
-    }
-
-    execute_script(cx, global, script_name);
-
-#ifdef HAVE_COMPARTMENTS
-    JS_LeaveCrossCompartmentCall(call);
-#endif
-    FINISH_REQUEST(cx);
-
-    JS_DestroyContext(cx);
-    JS_DestroyRuntime(rt);
-    JS_ShutDown();
-
-    return gExitCode;
-}

Added: couchdb/trunk/src/couchdb/priv/couch_js/sm170.c
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/sm170.c?rev=1164346&view=auto
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/sm170.c (added)
+++ couchdb/trunk/src/couchdb/priv/couch_js/sm170.c Fri Sep  2 04:03:05 2011
@@ -0,0 +1,378 @@
+// 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <jsapi.h>
+#include "http.h"
+#include "utf8.h"
+#include "util.h"
+
+
+#ifdef JS_THREADSAFE
+#define SETUP_REQUEST(cx) \
+    JS_SetContextThread(cx); \
+    JS_BeginRequest(cx);
+#define FINISH_REQUEST(cx) \
+    JS_EndRequest(cx); \
+    JS_ClearContextThread(cx);
+#else
+#define SETUP_REQUEST(cx)
+#define FINISH_REQUEST(cx)
+#endif
+
+
+static JSBool
+req_ctor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    return http_ctor(cx, obj);
+}
+
+
+static void 
+req_dtor(JSContext* cx, JSObject* obj)
+{
+    http_dtor(cx, obj);
+}
+
+
+static JSBool
+req_open(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    JSBool ret = JS_FALSE;
+
+    if(argc == 2) {
+        ret = http_open(cx, obj, argv[0], argv[1], JSVAL_FALSE);
+    } else if(argc == 3) {
+        ret = http_open(cx, obj, argv[0], argv[1], argv[2]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.open");
+    }
+
+    *rval = JSVAL_VOID;
+    return ret;
+}
+
+
+static JSBool
+req_set_hdr(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    JSBool ret = JS_FALSE;
+    if(argc == 2) {
+        ret = http_set_hdr(cx, obj, argv[0], argv[1]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.set_header");
+    }
+
+    *rval = JSVAL_VOID;
+    return ret;
+}
+
+
+static JSBool
+req_send(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    JSBool ret = JS_FALSE;
+    if(argc == 1) {
+        ret = http_send(cx, obj, argv[0]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.send");
+    }
+
+    *rval = JSVAL_VOID;
+    return ret;
+}
+
+
+static JSBool
+req_status(JSContext* cx, JSObject* obj, jsval idval, jsval* rval)
+{
+    int status = http_status(cx, obj);
+    if(status < 0)
+        return JS_FALSE;
+
+    if(INT_FITS_IN_JSVAL(status)) {
+        *rval = INT_TO_JSVAL(status);
+        return JS_TRUE;
+    } else {
+        JS_ReportError(cx, "Invalid HTTP status.");
+        return JS_FALSE;
+    }
+}
+
+
+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;
+
+    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);
+    *rval = JSVAL_VOID;
+    return JS_TRUE;
+}
+
+
+static JSBool
+print(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    couch_print(cx, argc, argv);
+    *rval = JSVAL_VOID;
+    return JS_TRUE;
+}
+
+
+static JSBool
+quit(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    int exit_code = 0;
+    JS_ConvertArguments(cx, argc, argv, "/i", &exit_code);
+    exit(exit_code);
+}
+
+
+static JSBool
+readline(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    JSString* line;
+
+    /* GC Occasionally */
+    JS_MaybeGC(cx);
+
+    line = couch_readline(cx, stdin);
+    if(line == NULL) return JS_FALSE;
+
+    *rval = STRING_TO_JSVAL(line);
+    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) {
+        *rval = JSVAL_VOID;
+        return JS_TRUE;
+    }
+
+    if(JS_SealObject(cx, obj, deep) != JS_TRUE)
+        return JS_FALSE;
+
+    *rval = JSVAL_VOID;
+    return JS_TRUE;
+}
+
+
+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,
+    req_dtor,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+
+JSPropertySpec CouchHTTPProperties[] = {
+    {"status", 0, JSPROP_READONLY, req_status, NULL},
+    {0, 0, 0, 0, 0}
+};
+
+
+JSFunctionSpec CouchHTTPFunctions[] = {
+    {"_open", req_open, 3, 0, 0},
+    {"_setRequestHeader", req_set_hdr, 2, 0, 0},
+    {"_send", req_send, 1, 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
+};
+
+
+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}
+};
+
+
+int
+main(int argc, const char* argv[])
+{
+    JSRuntime* rt = NULL;
+    JSContext* cx = NULL;
+    JSObject* global = NULL;
+    JSObject* klass = NULL;
+    JSScript* script;
+    JSString* scriptsrc;
+    jschar* schars;
+    size_t slen;
+    jsval sroot;
+    jsval result;
+
+    couch_args* args = couch_parse_args(argc, argv);
+    
+    rt = JS_NewRuntime(64L * 1024L * 1024L);
+    if(rt == NULL)
+        return 1;
+
+    cx = JS_NewContext(rt, args->stack_size);
+    if(cx == NULL)
+        return 1;
+
+    JS_SetErrorReporter(cx, couch_error);
+    JS_ToggleOptions(cx, JSOPTION_XML);
+    
+    SETUP_REQUEST(cx);
+
+    global = JS_NewObject(cx, &global_class, NULL, NULL);
+    if(global == NULL)
+        return 1;
+
+    JS_SetGlobalObject(cx, global);
+    
+    if(!JS_InitStandardClasses(cx, global))
+        return 1;
+
+    if(couch_load_funcs(cx, global, global_functions) != JS_TRUE)
+        return 1;
+ 
+    if(args->use_http) {
+        http_check_enabled();
+
+        klass = JS_InitClass(
+            cx, global,
+            NULL,
+            &CouchHTTPClass, req_ctor,
+            0,
+            CouchHTTPProperties, CouchHTTPFunctions,
+            NULL, NULL
+        );
+
+        if(!klass)
+        {
+            fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
+            exit(2);
+        }
+    } 
+
+    // Convert script source to jschars.
+    scriptsrc = dec_string(cx, args->script, strlen(args->script));
+    if(!scriptsrc)
+        return 1;
+
+    schars = JS_GetStringChars(scriptsrc);
+    slen = JS_GetStringLength(scriptsrc);
+    
+    // Root it so GC doesn't collect it.
+    sroot = STRING_TO_JSVAL(scriptsrc); 
+    if(JS_AddRoot(cx, &sroot) != JS_TRUE) {
+        fprintf(stderr, "Internal root error.\n");
+        return 1;
+    }
+
+    // Compile and run
+    script = JS_CompileUCScript(cx, global, schars, slen, args->script_name, 1);
+    if(!script) {
+        fprintf(stderr, "Failed to compile script.\n");
+        return 1;
+    }
+    
+    JS_ExecuteScript(cx, global, script, &result);
+    
+    // Warning message if we don't remove it.
+    JS_RemoveRoot(cx, &sroot);
+
+    FINISH_REQUEST(cx);
+    JS_DestroyContext(cx);
+    JS_DestroyRuntime(rt);
+    JS_ShutDown();
+
+    return 0;
+}

Added: couchdb/trunk/src/couchdb/priv/couch_js/sm180.c
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/sm180.c?rev=1164346&view=auto
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/sm180.c (added)
+++ couchdb/trunk/src/couchdb/priv/couch_js/sm180.c Fri Sep  2 04:03:05 2011
@@ -0,0 +1,387 @@
+// 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <jsapi.h>
+#include "http.h"
+#include "utf8.h"
+#include "util.h"
+
+
+#define SETUP_REQUEST(cx) \
+    JS_SetContextThread(cx); \
+    JS_BeginRequest(cx);
+#define FINISH_REQUEST(cx) \
+    JS_EndRequest(cx); \
+    JS_ClearContextThread(cx);
+
+
+static JSBool
+req_ctor(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
+{
+    return http_ctor(cx, obj);
+}
+
+
+static void 
+req_dtor(JSContext* cx, JSObject* obj)
+{
+    http_dtor(cx, obj);
+}
+
+
+static JSBool
+req_open(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    jsval* argv = JS_ARGV(cx, vp);
+    JSBool ret = JS_FALSE;
+
+    if(argc == 2) {
+        ret = http_open(cx, obj, argv[0], argv[1], JSVAL_FALSE);
+    } else if(argc == 3) {
+        ret = http_open(cx, obj, argv[0], argv[1], argv[2]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.open");
+    }
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return ret;
+}
+
+
+static JSBool
+req_set_hdr(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    jsval* argv = JS_ARGV(cx, vp);
+    JSBool ret = JS_FALSE;
+
+    if(argc == 2) {
+        ret = http_set_hdr(cx, obj, argv[0], argv[1]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.set_header");
+    }
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return ret;
+}
+
+
+static JSBool
+req_send(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    jsval* argv = JS_ARGV(cx, vp);
+    JSBool ret = JS_FALSE;
+
+    if(argc == 1) {
+        ret = http_send(cx, obj, argv[0]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.send");
+    }
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return ret;
+}
+
+
+static JSBool
+req_status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp)
+{
+    int status = http_status(cx, obj);
+    if(status < 0)
+        return JS_FALSE;
+
+    if(INT_FITS_IN_JSVAL(status)) {
+        JS_SET_RVAL(cx, vp, INT_TO_JSVAL(status));
+        return JS_TRUE;
+    } else {
+        JS_ReportError(cx, "Invalid HTTP status.");
+        return JS_FALSE;
+    }
+}
+
+
+static JSBool
+evalcx(JSContext *cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    JSString *str;
+    JSObject *sandbox;
+    JSContext *subcx;
+    const jschar *src;
+    size_t srclen;
+    jsval rval;
+    JSBool ret = JS_FALSE;
+
+    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) {
+        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sandbox));
+    } else {
+        JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, &rval);
+        JS_SET_RVAL(cx, vp, rval);
+    }
+    
+    ret = JS_TRUE;
+
+done:
+    FINISH_REQUEST(subcx);
+    JS_DestroyContext(subcx);
+    return ret;
+}
+
+
+static JSBool
+gc(JSContext* cx, uintN argc, jsval* vp)
+{
+    JS_GC(cx);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}
+
+
+static JSBool
+print(JSContext* cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    couch_print(cx, argc, argv);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}
+
+
+static JSBool
+quit(JSContext* cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    int exit_code = 0;
+    JS_ConvertArguments(cx, argc, argv, "/i", &exit_code);
+    exit(exit_code);
+}
+
+
+static JSBool
+readline(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSString* line;
+
+    /* GC Occasionally */
+    JS_MaybeGC(cx);
+
+    line = couch_readline(cx, stdin);
+    if(line == NULL) return JS_FALSE;
+
+    JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(line));
+    return JS_TRUE;
+}
+
+
+static JSBool
+seal(JSContext* cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    JSObject *target;
+    JSBool deep = JS_FALSE;
+
+    if(!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
+        return JS_FALSE;
+
+    if(!target) {
+        JS_SET_RVAL(cx, vp, JSVAL_VOID);
+        return JS_TRUE;
+    }
+
+    if(JS_SealObject(cx, target, deep) != JS_TRUE)
+        return JS_FALSE;
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}
+
+
+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,
+    req_dtor,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+
+JSPropertySpec CouchHTTPProperties[] = {
+    {"status", 0, JSPROP_READONLY, req_status, NULL},
+    {0, 0, 0, 0, 0}
+};
+
+
+JSFunctionSpec CouchHTTPFunctions[] = {
+    JS_FS("_open", (JSNative) req_open, 3, JSFUN_FAST_NATIVE, 0),
+    JS_FS("_setRequestHeader", (JSNative) req_set_hdr, 2, JSFUN_FAST_NATIVE, 0),
+    JS_FS("_send", (JSNative) req_send, 1, JSFUN_FAST_NATIVE, 0),
+    JS_FS_END
+};
+
+
+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
+};
+
+
+static JSFunctionSpec global_functions[] = {
+    JS_FS("evalcx", (JSNative) evalcx, 0, JSFUN_FAST_NATIVE, 0),
+    JS_FS("gc", (JSNative) gc, 0, JSFUN_FAST_NATIVE, 0),
+    JS_FS("print", (JSNative) print, 0, JSFUN_FAST_NATIVE, 0),
+    JS_FS("quit", (JSNative) quit, 0, JSFUN_FAST_NATIVE, 0),
+    JS_FS("readline", (JSNative) readline, 0, JSFUN_FAST_NATIVE, 0),
+    JS_FS("seal", (JSNative) seal, 0, JSFUN_FAST_NATIVE, 0),
+    JS_FS_END
+};
+
+
+int
+main(int argc, const char* argv[])
+{
+    JSRuntime* rt = NULL;
+    JSContext* cx = NULL;
+    JSObject* global = NULL;
+    JSObject* klass = NULL;
+    JSScript* script;
+    JSString* scriptsrc;
+    jschar* schars;
+    size_t slen;
+    jsval sroot;
+    jsval result;
+
+    couch_args* args = couch_parse_args(argc, argv);
+    
+    rt = JS_NewRuntime(64L * 1024L * 1024L);
+    if(rt == NULL)
+        return 1;
+
+    cx = JS_NewContext(rt, args->stack_size);
+    if(cx == NULL)
+        return 1;
+
+    JS_SetErrorReporter(cx, couch_error);
+    JS_ToggleOptions(cx, JSOPTION_XML);
+    
+    SETUP_REQUEST(cx);
+
+    global = JS_NewObject(cx, &global_class, NULL, NULL);
+    if(global == NULL)
+        return 1;
+
+    JS_SetGlobalObject(cx, global);
+    
+    if(!JS_InitStandardClasses(cx, global))
+        return 1;
+
+    if(couch_load_funcs(cx, global, global_functions) != JS_TRUE)
+        return 1;
+ 
+    if(args->use_http) {
+        http_check_enabled();
+
+        klass = JS_InitClass(
+            cx, global,
+            NULL,
+            &CouchHTTPClass, req_ctor,
+            0,
+            CouchHTTPProperties, CouchHTTPFunctions,
+            NULL, NULL
+        );
+
+        if(!klass)
+        {
+            fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
+            exit(2);
+        }
+    } 
+
+    // Convert script source to jschars.
+    scriptsrc = dec_string(cx, args->script, strlen(args->script));
+    if(!scriptsrc)
+        return 1;
+
+    schars = JS_GetStringChars(scriptsrc);
+    slen = JS_GetStringLength(scriptsrc);
+    
+    // Root it so GC doesn't collect it.
+    sroot = STRING_TO_JSVAL(scriptsrc); 
+    if(JS_AddRoot(cx, &sroot) != JS_TRUE) {
+        fprintf(stderr, "Internal root error.\n");
+        return 1;
+    }
+
+    // Compile and run
+    script = JS_CompileUCScript(cx, global, schars, slen, args->script_name, 1);
+    if(!script) {
+        fprintf(stderr, "Failed to compile script.\n");
+        return 1;
+    }
+    
+    JS_ExecuteScript(cx, global, script, &result);
+
+    // Warning message if we don't remove it.
+    JS_RemoveRoot(cx, &sroot);
+
+    FINISH_REQUEST(cx);
+    JS_DestroyContext(cx);
+    JS_DestroyRuntime(rt);
+    JS_ShutDown();
+
+    return 0;
+}

Added: couchdb/trunk/src/couchdb/priv/couch_js/sm185.c
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/sm185.c?rev=1164346&view=auto
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/sm185.c (added)
+++ couchdb/trunk/src/couchdb/priv/couch_js/sm185.c Fri Sep  2 04:03:05 2011
@@ -0,0 +1,401 @@
+// 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <jsapi.h>
+#include "http.h"
+#include "utf8.h"
+#include "util.h"
+
+
+#define SETUP_REQUEST(cx) \
+    JS_SetContextThread(cx); \
+    JS_BeginRequest(cx);
+#define FINISH_REQUEST(cx) \
+    JS_EndRequest(cx); \
+    JS_ClearContextThread(cx);
+
+
+static JSClass global_class = {
+    "GlobalClass",
+    JSCLASS_GLOBAL_FLAGS,
+    JS_PropertyStub,
+    JS_PropertyStub,
+    JS_PropertyStub,
+    JS_StrictPropertyStub,
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    JS_FinalizeStub,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+
+static JSBool
+req_ctor(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSBool ret;
+    JSObject* obj = JS_NewObjectForConstructor(cx, vp);
+    if(!obj) {
+        JS_ReportError(cx, "Failed to create CouchHTTP instance.\n");
+        return JS_FALSE;
+    }
+    ret = http_ctor(cx, obj);
+    JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
+    return ret;
+}
+
+
+static void 
+req_dtor(JSContext* cx, JSObject* obj)
+{
+    http_dtor(cx, obj);
+}
+
+
+static JSBool
+req_open(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    jsval* argv = JS_ARGV(cx, vp);
+    JSBool ret = JS_FALSE;
+
+    if(argc == 2) {
+        ret = http_open(cx, obj, argv[0], argv[1], JSVAL_FALSE);
+    } else if(argc == 3) {
+        ret = http_open(cx, obj, argv[0], argv[1], argv[2]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.open");
+    }
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return ret;
+}
+
+
+static JSBool
+req_set_hdr(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    jsval* argv = JS_ARGV(cx, vp);
+    JSBool ret = JS_FALSE;
+
+    if(argc == 2) {
+        ret = http_set_hdr(cx, obj, argv[0], argv[1]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.set_header");
+    }
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return ret;
+}
+
+
+static JSBool
+req_send(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSObject* obj = JS_THIS_OBJECT(cx, vp);
+    jsval* argv = JS_ARGV(cx, vp);
+    JSBool ret = JS_FALSE;
+
+    if(argc == 1) {
+        ret = http_send(cx, obj, argv[0]);
+    } else {
+        JS_ReportError(cx, "Invalid call to CouchHTTP.send");
+    }
+
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return ret;
+}
+
+
+static JSBool
+req_status(JSContext* cx, JSObject* obj, jsid pid, jsval* vp)
+{
+    int status = http_status(cx, obj);
+    if(status < 0)
+        return JS_FALSE;
+
+    JS_SET_RVAL(cx, vp, INT_TO_JSVAL(status));
+    return JS_TRUE;
+}
+
+
+static JSBool
+evalcx(JSContext *cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    JSString* str;
+    JSObject* sandbox;
+    JSObject* global;
+    JSContext* subcx;
+    JSCrossCompartmentCall* call = NULL;
+    const jschar* src;
+    size_t srclen;
+    jsval rval;
+    JSBool ret = JS_FALSE;
+
+    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_GetStringCharsAndLength(cx, str, &srclen);
+
+    // Re-use the compartment associated with the main context,
+    // rather than creating a new compartment */
+    global = JS_GetGlobalObject(cx);
+    if(global == NULL) goto done;
+    call = JS_EnterCrossCompartmentCall(subcx, global);
+
+    if(!sandbox) {
+        sandbox = JS_NewGlobalObject(subcx, &global_class);
+        if(!sandbox || !JS_InitStandardClasses(subcx, sandbox)) {
+            goto done;
+        }
+    }
+
+    if(srclen == 0) {
+        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(sandbox));
+    } else {
+        JS_EvaluateUCScript(subcx, sandbox, src, srclen, NULL, 0, &rval);
+        JS_SET_RVAL(cx, vp, rval);
+    }
+    
+    ret = JS_TRUE;
+
+done:
+    JS_LeaveCrossCompartmentCall(call);
+    FINISH_REQUEST(subcx);
+    JS_DestroyContext(subcx);
+    return ret;
+}
+
+
+static JSBool
+gc(JSContext* cx, uintN argc, jsval* vp)
+{
+    JS_GC(cx);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}
+
+
+static JSBool
+print(JSContext* cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    couch_print(cx, argc, argv);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return JS_TRUE;
+}
+
+
+static JSBool
+quit(JSContext* cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    int exit_code = 0;
+    JS_ConvertArguments(cx, argc, argv, "/i", &exit_code);
+    exit(exit_code);
+}
+
+
+static JSBool
+readline(JSContext* cx, uintN argc, jsval* vp)
+{
+    JSString* line;
+
+    /* GC Occasionally */
+    JS_MaybeGC(cx);
+
+    line = couch_readline(cx, stdin);
+    if(line == NULL) return JS_FALSE;
+
+    JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(line));
+    return JS_TRUE;
+}
+
+
+static JSBool
+seal(JSContext* cx, uintN argc, jsval* vp)
+{
+    jsval* argv = JS_ARGV(cx, vp);
+    JSObject *target;
+    JSBool deep = JS_FALSE;
+    JSBool ret;
+
+    if(!JS_ConvertArguments(cx, argc, argv, "o/b", &target, &deep))
+        return JS_FALSE;
+
+    if(!target) {
+        JS_SET_RVAL(cx, vp, JSVAL_VOID);
+        return JS_TRUE;
+    }
+
+    
+    ret = deep ? JS_DeepFreezeObject(cx, target) : JS_FreezeObject(cx, target);
+    JS_SET_RVAL(cx, vp, JSVAL_VOID);
+    return ret;
+}
+
+
+JSClass CouchHTTPClass = {
+    "CouchHTTP",
+    JSCLASS_HAS_PRIVATE
+        | JSCLASS_CONSTRUCT_PROTOTYPE
+        | JSCLASS_HAS_RESERVED_SLOTS(2),
+    JS_PropertyStub,
+    JS_PropertyStub,
+    JS_PropertyStub,
+    JS_StrictPropertyStub,
+    JS_EnumerateStub,
+    JS_ResolveStub,
+    JS_ConvertStub,
+    req_dtor,
+    JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+
+JSPropertySpec CouchHTTPProperties[] = {
+    {"status", 0, JSPROP_READONLY, req_status, NULL},
+    {0, 0, 0, 0, 0}
+};
+
+
+JSFunctionSpec CouchHTTPFunctions[] = {
+    JS_FS("_open", req_open, 3, 0),
+    JS_FS("_setRequestHeader", req_set_hdr, 2, 0),
+    JS_FS("_send", req_send, 1, 0),
+    JS_FS_END
+};
+
+
+static JSFunctionSpec global_functions[] = {
+    JS_FS("evalcx", evalcx, 0, 0),
+    JS_FS("gc", gc, 0, 0),
+    JS_FS("print", print, 0, 0),
+    JS_FS("quit", quit, 0, 0),
+    JS_FS("readline", readline, 0, 0),
+    JS_FS("seal", seal, 0, 0),
+    JS_FS_END
+};
+
+
+int
+main(int argc, const char* argv[])
+{
+    JSRuntime* rt = NULL;
+    JSContext* cx = NULL;
+    JSObject* global = NULL;
+    JSCrossCompartmentCall *call = NULL;
+    JSObject* klass = NULL;
+    JSObject* script;
+    JSString* scriptsrc;
+    const jschar* schars;
+    size_t slen;
+    jsval sroot;
+    jsval result;
+
+    couch_args* args = couch_parse_args(argc, argv);
+
+    rt = JS_NewRuntime(64L * 1024L * 1024L);
+    if(rt == NULL)
+        return 1;
+
+    cx = JS_NewContext(rt, args->stack_size);
+    if(cx == NULL)
+        return 1;
+
+    JS_SetErrorReporter(cx, couch_error);
+    JS_ToggleOptions(cx, JSOPTION_XML);
+    
+    SETUP_REQUEST(cx);
+
+    global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
+    if(global == NULL)
+        return 1;
+
+    call = JS_EnterCrossCompartmentCall(cx, global);
+
+    JS_SetGlobalObject(cx, global);
+    
+    if(!JS_InitStandardClasses(cx, global))
+        return 1;
+
+    if(couch_load_funcs(cx, global, global_functions) != JS_TRUE)
+        return 1;
+ 
+    if(args->use_http) {
+        http_check_enabled();
+
+        klass = JS_InitClass(
+            cx, global,
+            NULL,
+            &CouchHTTPClass, req_ctor,
+            0,
+            CouchHTTPProperties, CouchHTTPFunctions,
+            NULL, NULL
+        );
+
+        if(!klass)
+        {
+            fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
+            exit(2);
+        }
+    } 
+
+    // Convert script source to jschars.
+    scriptsrc = dec_string(cx, args->script, strlen(args->script));
+    if(!scriptsrc)
+        return 1;
+
+    schars = JS_GetStringCharsAndLength(cx, scriptsrc, &slen);
+    
+    // Root it so GC doesn't collect it.
+    sroot = STRING_TO_JSVAL(scriptsrc); 
+    if(JS_AddValueRoot(cx, &sroot) != JS_TRUE) {
+        fprintf(stderr, "Internal root error.\n");
+        return 1;
+    }
+
+    // Compile and run
+    script = JS_CompileUCScript(cx, global, schars, slen, args->script_name, 1);
+    if(!script) {
+        fprintf(stderr, "Failed to compile script.\n");
+        return 1;
+    }
+    
+    JS_ExecuteScript(cx, global, script, &result);
+
+    // Warning message if we don't remove it.
+    JS_RemoveValueRoot(cx, &sroot);
+
+    JS_LeaveCrossCompartmentCall(call);
+    FINISH_REQUEST(cx);
+    JS_DestroyContext(cx);
+    JS_DestroyRuntime(rt);
+    JS_ShutDown();
+
+    return 0;
+}

Added: couchdb/trunk/src/couchdb/priv/couch_js/util.c
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/util.c?rev=1164346&view=auto
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/util.c (added)
+++ couchdb/trunk/src/couchdb/priv/couch_js/util.c Fri Sep  2 04:03:05 2011
@@ -0,0 +1,237 @@
+// 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 <stdlib.h>
+#include <string.h>
+
+#include <jsapi.h>
+
+#include "util.h"
+#include "utf8.h"
+
+
+char*
+slurp_file(char* buf, const char* file)
+{
+    FILE* fp;
+    char fbuf[16384];
+    char* tmp;
+    size_t nread = 0;
+    size_t buflen = 0;
+
+    if(strcmp(file, "-") == 0) {
+        fp = stdin;
+    } else {
+        fp = fopen(file, "r");
+        if(fp == NULL) {
+            fprintf(stderr, "Failed to read file: %s\n", file);
+            exit(3);
+        }
+    }
+
+    while((nread = fread(fbuf, 1, 16384, fp)) > 0) {
+        if(buf == NULL) {
+            buflen = nread;
+            buf = (char*) malloc(nread + 1);
+            if(buf == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(buf, fbuf, buflen);
+            buf[buflen] = '\0';
+        } else {
+            buflen = strlen(buf);
+            tmp = (char*) malloc(buflen + nread + 1);
+            if(tmp == NULL) {
+                fprintf(stderr, "Out of memory.\n");
+                exit(3);
+            }
+            memcpy(tmp, buf, buflen);
+            memcpy(tmp+buflen, fbuf, nread);
+            tmp[buflen+nread] = '\0';
+            free(buf);
+            buf = tmp;
+        }
+    }
+    return buf;
+}
+
+couch_args*
+couch_parse_args(int argc, const char* argv[])
+{
+    couch_args* args;
+    int i = 1;
+
+    args = (couch_args*) malloc(sizeof(couch_args));
+    if(args == NULL)
+        return NULL;
+
+    memset(args, '\0', sizeof(couch_args));
+    args->stack_size = 8L * 1024L;
+
+    while(i < argc) {
+        if(strcmp("--http", argv[i]) == 0) {
+            args->use_http = 1;
+        } else if(strcmp("--stack-size", argv[i]) == 0) {
+            args->stack_size = atoi(argv[i+1]);
+            if(args->stack_size <= 0) {
+                fprintf(stderr, "Invalid stack size.\n");
+                exit(2);
+            }
+        } else {
+            args->script = slurp_file(args->script, argv[i]);
+            if(args->script_name == NULL) {
+                if(strcmp(argv[i], "-") == 0) {
+                    args->script_name = "<stdin>";
+                } else {
+                    args->script_name = argv[i];
+                }
+            } else {
+                args->script_name = "<multiple_files>";
+            }
+        }
+        i++;
+    }
+
+    if(args->script_name == NULL || args->script == NULL) {
+        fprintf(stderr, "No script provided.\n");
+        exit(3);
+    }
+
+    return args;
+}
+
+
+int
+couch_fgets(char* buf, int size, FILE* fp)
+{
+    int n, i, c;
+
+    if(size <= 0) return -1;
+    n = size - 1;
+
+    for(i = 0; i < n && (c = getc(fp)) != EOF; i++) {
+        buf[i] = c;
+        if(c == '\n') {
+            i++;
+            break;
+        }
+    }
+
+    buf[i] = '\0';
+    return i;
+}
+
+
+JSString*
+couch_readline(JSContext* cx, FILE* fp)
+{
+    JSString* str;
+    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 = couch_fgets(bytes+used, byteslen-used, fp)) > 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;
+    }
+
+    // Treat empty strings specially
+    if(used == 0) {
+        JS_free(cx, bytes);
+        return JSVAL_TO_STRING(JS_GetEmptyStringValue(cx));
+    }
+
+    // Shring the buffer to the actual data size
+    tmp = JS_realloc(cx, bytes, used);
+    if(!tmp) {
+        JS_free(cx, bytes);
+        return NULL;
+    }
+    bytes = tmp;
+    byteslen = used;
+
+    str = dec_string(cx, bytes, byteslen);
+    JS_free(cx, bytes);
+    return str;
+}
+
+
+JSObject*
+couch_readfile(JSContext* cx, FILE* fp)
+{
+    return NULL;    
+}
+
+
+void
+couch_print(JSContext* cx, uintN argc, jsval* argv)
+{
+    char *bytes;
+    uintN i;
+
+    for(i = 0; i < argc; i++)
+    {
+        bytes = enc_string(cx, argv[i], NULL);
+        if(!bytes) return;
+
+        fprintf(stdout, "%s%s", i ? " " : "", bytes);
+        JS_free(cx, bytes);
+    }
+
+    fputc('\n', stdout);
+    fflush(stdout);
+}
+
+
+void
+couch_error(JSContext* cx, const char* mesg, JSErrorReport* report)
+{
+    if(!report || !JSREPORT_IS_WARNING(report->flags))
+    {
+        fprintf(stderr, "[couchjs] %s\n", mesg);
+    }
+}
+
+
+JSBool
+couch_load_funcs(JSContext* cx, JSObject* obj, JSFunctionSpec* funcs)
+{
+    JSFunctionSpec* f;
+    for(f = funcs; f->name != NULL; f++) {
+        if(!JS_DefineFunction(cx, obj, f->name, f->call, f->nargs, f->flags)) {
+            fprintf(stderr, "Failed to create function: %s\n", f->name);
+            return JS_FALSE;
+        }
+    }
+    return JS_TRUE;
+}
+

Added: couchdb/trunk/src/couchdb/priv/couch_js/util.h
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/priv/couch_js/util.h?rev=1164346&view=auto
==============================================================================
--- couchdb/trunk/src/couchdb/priv/couch_js/util.h (added)
+++ couchdb/trunk/src/couchdb/priv/couch_js/util.h Fri Sep  2 04:03:05 2011
@@ -0,0 +1,34 @@
+// 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 COUCHJS_UTIL_H
+#define COUCHJS_UTIL_H
+
+#include <jsapi.h>
+
+typedef struct {
+    int         use_http;
+    int         stack_size;
+    const char* script_name;
+    char*       script;
+} couch_args;
+
+void couch_usage();
+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);
+void couch_print(JSContext* cx, uintN argc, jsval* argv);
+void couch_error(JSContext* cx, const char* mesg, JSErrorReport* report);
+JSBool couch_load_funcs(JSContext* cx, JSObject* obj, JSFunctionSpec* funcs);
+
+
+#endif // Included util.h

Modified: couchdb/trunk/test/javascript/run.tpl
URL: http://svn.apache.org/viewvc/couchdb/trunk/test/javascript/run.tpl?rev=1164346&r1=1164345&r2=1164346&view=diff
==============================================================================
--- couchdb/trunk/test/javascript/run.tpl (original)
+++ couchdb/trunk/test/javascript/run.tpl Fri Sep  2 04:03:05 2011
@@ -44,4 +44,4 @@ cat $SCRIPT_DIR/json2.js \
 	$TEST_SRC \
 	$JS_TEST_DIR/couch_http.js \
 	$JS_TEST_DIR/cli_runner.js \
-    | $COUCHJS -H -
+    | $COUCHJS --http -



Mime
View raw message