couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jch...@apache.org
Subject svn commit: r703276 - in /incubator/couchdb/trunk: share/www/script/couch_tests.js src/couchdb/Makefile.am src/couchdb/couch_js.c src/couchdb/curlhelper.c src/couchdb/curlhelper.h test/runner.sh test/test.js
Date Thu, 09 Oct 2008 22:04:47 GMT
Author: jchris
Date: Thu Oct  9 15:04:46 2008
New Revision: 703276

URL: http://svn.apache.org/viewvc?rev=703276&view=rev
Log:
make check now runs the JavaScript test suite

Added:
    incubator/couchdb/trunk/src/couchdb/curlhelper.c   (with props)
    incubator/couchdb/trunk/src/couchdb/curlhelper.h   (with props)
    incubator/couchdb/trunk/test/test.js   (with props)
Modified:
    incubator/couchdb/trunk/share/www/script/couch_tests.js
    incubator/couchdb/trunk/src/couchdb/Makefile.am
    incubator/couchdb/trunk/src/couchdb/couch_js.c
    incubator/couchdb/trunk/test/runner.sh

Modified: incubator/couchdb/trunk/share/www/script/couch_tests.js
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/share/www/script/couch_tests.js?rev=703276&r1=703275&r2=703276&view=diff
==============================================================================
--- incubator/couchdb/trunk/share/www/script/couch_tests.js [utf-8] (original)
+++ incubator/couchdb/trunk/share/www/script/couch_tests.js [utf-8] Thu Oct  9 15:04:46 2008
@@ -10,6 +10,11 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
+// Used by replication test
+CouchDB.host = (typeof window == 'undefined' || !window) ? 
+                  "127.0.0.1" : window.location.host;
+CouchDB.port = 5984;
+
 var tests = {
 
   // Do some basic tests.
@@ -1556,7 +1561,7 @@
 
   replication: function(debug) {
     if (debug) debugger;
-    var host = window.location.host;
+    var host = CouchDB.host;
     var dbPairs = [
       {source:"test_suite_db_a",
         target:"test_suite_db_b"},

Modified: incubator/couchdb/trunk/src/couchdb/Makefile.am
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/couchdb/Makefile.am?rev=703276&r1=703275&r2=703276&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/couchdb/Makefile.am (original)
+++ incubator/couchdb/trunk/src/couchdb/Makefile.am Thu Oct  9 15:04:46 2008
@@ -24,7 +24,8 @@
 couch_erl_driver_la_LIBADD = -licuuc -licudata -licui18n
 
 locallibbin_PROGRAMS = couchjs
-couchjs_SOURCES = couch_js.c
+couchjs_SOURCES = couch_js.c curlhelper.c
+couchjs_LDADD = -lcurl -lgssapi_krb5
 
 couchinclude_DATA = couch_db.hrl
 

Modified: incubator/couchdb/trunk/src/couchdb/couch_js.c
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/couchdb/couch_js.c?rev=703276&r1=703275&r2=703276&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/couchdb/couch_js.c (original)
+++ incubator/couchdb/trunk/src/couchdb/couch_js.c Thu Oct  9 15:04:46 2008
@@ -13,8 +13,16 @@
 
 */
 
+#include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
+#include "curlhelper.h"
 #include <jsapi.h>
+#include <curl/curl.h>
+
+#ifndef CURLOPT_COPYPOSTFIELDS
+   #define CURLOPT_COPYPOSTFIELDS 10165
+#endif
 
 int gExitCode = 0;
 int gStackChunkSize = 8L * 1024L;
@@ -401,6 +409,785 @@
         fprintf(stderr, "%s\n", message);
 }
 
+JSBool ThrowError(JSContext *cx, const char *message)
+{
+    void *mark;
+    jsval *args;
+    jsval exc;
+
+    printf("%s\n",message);
+
+    args = JS_PushArguments(cx, &mark, "s", message);
+    if (args) {
+        if (JS_CallFunctionName(cx, JS_GetGlobalObject(cx),
+                                "Error", 1, args, &exc))
+            JS_SetPendingException(cx, exc);
+        JS_PopArguments(cx, mark);
+    }
+
+    return JS_FALSE;
+}
+
+typedef struct buffer_counter {
+ Buffer buffer;
+ int pos;
+}* BufferCount;
+
+size_t curl_read(void *ptr, size_t size, size_t nmemb, void *stream) {
+  if( size == 0 || nmemb == 0) {
+    return 0;
+  }
+
+  char* databuffer = (char*)ptr;
+  Buffer b = ((BufferCount)stream)->buffer;
+  int* pos = &(((BufferCount)stream)->pos);
+
+  if((b->count - *pos) == 0) {
+    return 0;
+  }
+
+  int readlength = size*nmemb;
+  int spaceleft = b->count - *pos;
+  int i;
+
+  if(readlength < spaceleft) {
+    copy_Buffer(b,databuffer,*pos,readlength);
+    *(pos) += readlength;
+    return readlength;
+  } else {
+    copy_Buffer(b,databuffer,*pos,spaceleft);
+    *(pos) += spaceleft;
+    return spaceleft;
+  }
+}
+
+size_t curl_write(void *ptr, size_t size, size_t nmemb, void *stream) {
+  if( size == 0 || nmemb == 0 )
+    return 0;
+
+  char *data, *tmp;
+  Buffer b;
+
+  data = (char *)ptr;
+  b = (Buffer)stream;
+
+  append_Buffer(b,data,size*nmemb);
+
+  return size*nmemb;
+}
+
+// This uses MALLOC dont forget to free
+char* JSValToChar(JSContext* context, jsval* arg) {
+  if(!JSVAL_IS_STRING(*arg)) {
+    return NULL;
+  }
+
+  char *c, *tmp;
+  JSString *jsmsg;
+  size_t len;
+
+  jsmsg = JS_ValueToString(context,*arg);
+  len = JS_GetStringLength(jsmsg);
+  tmp = JS_GetStringBytes(jsmsg);
+      
+  c = (char*)malloc(len+1);
+  c[len] = '\0';
+
+  int i;
+ 
+  for(i = 0;i < len;i++) {
+    c[i] = tmp[i];
+  }
+
+  return c;
+}
+
+JSBool BufferToJSVal(JSContext *context, Buffer b, jsval *rval) {
+  char* c;
+  JSString *str;
+
+  // Important for char* to be JS_malloced, otherwise js wont let you use it in the NewString
method
+  c = JS_malloc(context, b->count * sizeof(char));
+  copy_Buffer(b,c,0,b->count);
+
+
+  /* Initialize a JSString object */
+  str = JS_NewString(context, c, b->count);
+
+  if (!str) {
+    JS_free(context, c);
+    return JS_FALSE;
+  }
+
+  // Set Return Value
+  *rval = STRING_TO_JSVAL(str);
+  if(rval == NULL) {
+    return JS_FALSE;
+  }
+  return JS_TRUE;
+}
+
+struct curl_slist* generateCurlHeaders(JSContext* context,jsval* arg) {
+  // If arg is an object then we go the header-hash route else return NULL
+
+  if(!JSVAL_IS_NULL(*arg)) {
+
+    struct curl_slist *slist = NULL;
+    JSObject* header_obj;
+
+    // If we fail to convert arg2 to an object. Error!
+    if(!JS_ValueToObject(context,*arg,&header_obj)) {
+      return NULL;
+    }
+
+    JSObject* iterator = JS_NewPropertyIterator(context,header_obj);
+    
+    jsval *jsProperty = JS_malloc(context,sizeof(jsval));
+    jsval *jsValue = JS_malloc(context,sizeof(jsval));
+    jsid *jsId = JS_malloc(context,sizeof(jsid));
+    
+    while(JS_NextProperty(context,iterator,jsId) == JS_TRUE) {
+
+      if(*jsId == JSVAL_VOID) {
+	break;
+      }
+
+      // TODO: Refactor this maybe make a JSValAppendBuffer method b/c that is what you really
want to do.
+
+      Buffer bTmp = init_Buffer();
+      JS_IdToValue(context,*jsId,jsProperty);
+      char* jsPropertyName = JSValToChar(context,jsProperty);
+
+      // TODO: Remove strlen =/
+      append_Buffer(bTmp,jsPropertyName,strlen(jsPropertyName));
+      append_Buffer(bTmp,": ",2);
+
+      JS_GetProperty(context,header_obj,jsPropertyName,jsValue);
+      char* jsPropertyValue = JSValToChar(context,jsValue);
+      // TODO: Remove strlen =/
+      append_Buffer(bTmp,jsPropertyValue,strlen(jsPropertyValue));
+      append_Buffer(bTmp,"",1);
+
+      slist = curl_slist_append(slist,bTmp->data);
+      
+      free_Buffer(bTmp);
+      free(jsPropertyValue);
+      free(jsPropertyName);
+    }
+
+    JS_free(context,jsProperty);
+    JS_free(context,jsValue);
+    JS_free(context,jsId);
+
+    return slist;
+
+  } else {
+    return NULL;
+  }
+}
+
+static JSBool
+GetHttp(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+  CURL* handle;
+  Buffer b;
+  char *url;
+  size_t charslen, readlen;
+
+  // Run GC
+  JS_MaybeGC(context);
+  
+  // Init Curl
+  if((handle = curl_easy_init()) == NULL) {
+    return JS_FALSE;
+  }
+
+  // Get URL
+  url = JSValToChar(context,argv);
+  if( url == NULL ) {
+    return ThrowError(context,"Unable to convert url (argument 0) to a string");
+  }
+
+  b = init_Buffer(); // Allocate buffer that will store the get resultant
+
+  // Configuration
+  curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEDATA,b);
+  curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEHEADER,b);
+  curl_easy_setopt(handle,CURLOPT_URL,url);
+  curl_easy_setopt(handle,CURLOPT_HTTPGET,1);
+  curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
+  curl_easy_setopt(handle,CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4);
+
+  struct curl_slist *slist = generateCurlHeaders(context,argv+1);
+  if(slist != NULL) {
+    curl_easy_setopt(handle,CURLOPT_HTTPHEADER,slist);
+  }
+
+  // Perform
+  int exitcode;
+
+  if((exitcode = curl_easy_perform(handle)) != 0) {
+    if(slist != NULL) {
+      curl_slist_free_all(slist);
+    }
+    curl_easy_cleanup(handle);
+    free(url);
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+
+  free(url);
+  if(slist != NULL) {
+    curl_slist_free_all(slist);
+  }
+
+  /* Treat the empty string specially */
+  if (b->count == 0) {
+    free_Buffer(b);
+    *rval = JS_GetEmptyStringValue(context);
+    curl_easy_cleanup(handle);
+    return JS_TRUE;
+  }
+
+  /* Shrink the buffer to the real size  and store its value in rval */
+  shrink_Buffer(b);
+  BufferToJSVal(context,b,rval);
+  
+  // Free Buffer
+  free_Buffer(b);
+
+  if(rval == NULL) {
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  JS_MaybeGC(context);
+
+  curl_easy_cleanup(handle);
+
+  return JS_TRUE;
+}
+
+static JSBool
+HeadHttp(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+  CURL* handle;
+  Buffer b;
+  char *url;
+  size_t charslen, readlen;
+
+  // Run GC
+  JS_MaybeGC(context);
+  
+  // Init Curl
+  if((handle = curl_easy_init()) == NULL) {
+    return JS_FALSE;
+  }
+
+  // Get URL
+  url = JSValToChar(context,argv);
+  if( url == NULL ) {
+    return ThrowError(context,"Unable to convert url (argument 0) to a string");
+  }
+
+  b = init_Buffer(); // Allocate buffer that will store the get resultant
+
+  // Configuration
+  // curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,curl_write);
+  // curl_easy_setopt(handle,CURLOPT_WRITEDATA,b);
+  curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEHEADER,b);
+  curl_easy_setopt(handle,CURLOPT_URL,url);
+  curl_easy_setopt(handle,CURLOPT_HTTPGET,0);
+  curl_easy_setopt(handle,CURLOPT_NOBODY,1);
+  curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
+  curl_easy_setopt(handle,CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4);
+
+  struct curl_slist *slist = generateCurlHeaders(context,argv+1);
+  if(slist != NULL) {
+    curl_easy_setopt(handle,CURLOPT_HTTPHEADER,slist);
+  }
+
+  // fprintf(stderr, "about to run HEAD request\n");
+
+  // Perform
+  int exitcode;
+
+  if((exitcode = curl_easy_perform(handle)) != 0) {
+    if(slist != NULL) {
+      curl_slist_free_all(slist);
+    }
+    curl_easy_cleanup(handle);
+    free(url);
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+  // fprintf(stderr, "ran ok HEAD request\n");
+
+  free(url);
+  if(slist != NULL) {
+    curl_slist_free_all(slist);
+  }
+
+  /* Treat the empty string specially */
+  if (b->count == 0) {
+    free_Buffer(b);
+    *rval = JS_GetEmptyStringValue(context);
+    curl_easy_cleanup(handle);
+    return JS_TRUE;
+  }
+
+  /* Shrink the buffer to the real size  and store its value in rval */
+  shrink_Buffer(b);
+  BufferToJSVal(context,b,rval);
+  
+  // Free Buffer
+  free_Buffer(b);
+
+  if(rval == NULL) {
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  JS_MaybeGC(context);
+
+  curl_easy_cleanup(handle);
+
+  return JS_TRUE;
+}
+
+
+static JSBool
+PostHttp(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+  CURL* handle;
+  Buffer b;
+  char *url, *body;
+  size_t charslen, readlen;
+
+  // Run GC
+  JS_MaybeGC(context);
+
+  // Init Curl
+  if((handle = curl_easy_init()) == NULL) {
+    return JS_FALSE;
+  }
+
+  // Get URL
+  if((url = JSValToChar(context,argv)) == NULL) {
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  // Initialize buffer
+  b = init_Buffer();
+
+  curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,curl_write);    // function that recieves
data
+  curl_easy_setopt(handle,CURLOPT_WRITEDATA,b);                 // buffer to write the data
to
+  curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEHEADER,b);
+  curl_easy_setopt(handle,CURLOPT_URL,url);                     // url
+  curl_easy_setopt(handle,CURLOPT_HTTPPOST,1);                  // Set Op. to post
+  curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);                // No Progress Meter
+  curl_easy_setopt(handle,CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4); // only ipv4
+
+  if((body = JSValToChar(context,argv+1)) == NULL) {            // Convert arg1 to a string
+    free(url);
+    free_Buffer(b);
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  curl_easy_setopt(handle,CURLOPT_COPYPOSTFIELDS,body);         // Curl wants '\0' terminated,
we oblige
+  free(body);
+
+  struct curl_slist *slist = generateCurlHeaders(context,argv+2); // Initialize Headers
+  if(slist != NULL) {
+    curl_easy_setopt(handle,CURLOPT_HTTPHEADER,slist);            
+  }
+
+  int exitcode;
+
+  if((exitcode = curl_easy_perform(handle)) != 0) {             // Perform
+    curl_slist_free_all(slist);
+    free(url);
+    free_Buffer(b);
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  free(url);
+  curl_slist_free_all(slist);
+
+  // Convert response back to javascript value and then clean
+  BufferToJSVal(context,b,rval);
+  free_Buffer(b);
+  curl_easy_cleanup(handle);
+
+  JS_MaybeGC(context);
+
+  if( rval == NULL ) {
+    return JS_FALSE;
+  }
+
+  return JS_TRUE;
+}
+
+#define CLEAN \
+  free_Buffer(b); \
+  free_Buffer(b_data->buffer); \
+  free(b_data);		       \
+  free(url)
+
+static JSBool
+PutHttp(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval){
+
+  Buffer b;
+  BufferCount b_data;
+  char *url, *data;
+  size_t charslen, readlen;
+  JSObject* header_obj;
+
+  // Run GC
+  JS_MaybeGC(context);
+
+  // Get URL
+  url = JSValToChar(context,argv);
+
+  // Allocate buffer that will store the get resultant
+  b = init_Buffer();
+  
+  // Allocate data buffer and move data into them
+  b_data = (BufferCount)malloc(sizeof(Buffer) + sizeof(int));
+  b_data->buffer = init_Buffer();
+  b_data->pos = 0;
+  
+  data = JSValToChar(context,(argv+1));
+  // TODO: remove strlen
+  append_Buffer(b_data->buffer,data,strlen(data));
+
+  free(data);
+
+  CURL* handle;
+
+  // Init Curl
+
+  if((handle = curl_easy_init()) == NULL) {
+    CLEAN;
+    return JS_FALSE;
+  }
+
+  // Configuration
+  curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEDATA,b);
+  curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEHEADER,b);
+  curl_easy_setopt(handle,CURLOPT_READFUNCTION,curl_read);
+  curl_easy_setopt(handle,CURLOPT_READDATA,b_data);
+  curl_easy_setopt(handle,CURLOPT_URL,url);
+  curl_easy_setopt(handle,CURLOPT_UPLOAD,1);
+
+  // Curl structure
+  struct curl_slist *slist = generateCurlHeaders(context,argv+2);
+  if(slist != NULL) {
+    curl_easy_setopt(handle,CURLOPT_HTTPHEADER,slist);
+  }
+
+  // Little Things
+  // No progress meter
+  curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
+  // Use only ipv4
+  curl_easy_setopt(handle,CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4);
+
+  // Perform
+  int exitcode;
+  
+  if((exitcode = curl_easy_perform(handle)) != 0) {
+    if(slist != NULL)
+      curl_slist_free_all(slist);
+    curl_easy_cleanup(handle);
+    CLEAN;
+    return JS_FALSE;
+  }
+
+  if(slist != NULL)
+    curl_slist_free_all(slist);
+  free_Buffer(b_data->buffer);
+  free(b_data);
+  free(url);
+
+  /* Treat the empty string specially */
+  if (b->count == 0) {
+    *rval = JS_GetEmptyStringValue(context);
+    curl_easy_cleanup(handle);
+    free_Buffer(b);
+    return JS_TRUE;
+  }
+
+  /* Shrink the buffer to the real size */
+  shrink_Buffer(b);
+
+  BufferToJSVal(context,b,rval);
+  
+  free_Buffer(b);
+
+  if(rval == NULL) {
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  JS_MaybeGC(context);
+
+  curl_easy_cleanup(handle);
+
+  return JS_TRUE;
+}
+
+static JSBool
+DelHttp(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+  Buffer b;
+  char *url;
+  size_t charslen, readlen;
+  char header_name[7];
+  strcpy(header_name,"DELETE");
+
+  // Run GC
+  JS_MaybeGC(context);
+
+  // Get URL
+  url = JSValToChar(context,argv);
+
+  // Allocate buffer that will store the del resultant
+  b = init_Buffer();
+
+  CURL* handle;
+
+  // Init Curl
+  if((handle = curl_easy_init()) == NULL) {
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+
+  // Configuration
+  curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEDATA,b);
+  curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEHEADER,b);
+  curl_easy_setopt(handle,CURLOPT_URL,url);
+  curl_easy_setopt(handle,CURLOPT_CUSTOMREQUEST,header_name);
+  curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
+  curl_easy_setopt(handle,CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4);
+
+  // Curl structure
+  struct curl_slist *slist = NULL;
+  if((slist = generateCurlHeaders(context,argv+1)) != NULL) {
+    curl_easy_setopt(handle,CURLOPT_HTTPHEADER,slist);
+  }
+
+  // Perform
+  int exitcode;
+
+  if((exitcode = curl_easy_perform(handle)) != 0) {
+    if(slist != NULL)
+      curl_slist_free_all(slist);
+    curl_easy_cleanup(handle);
+    free(url);
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+
+  if(slist != NULL)
+    curl_slist_free_all(slist);
+  free(url);
+
+  /* Treat the empty string specially */
+  if (b->count == 0) {
+    *rval = JS_GetEmptyStringValue(context);
+    curl_easy_cleanup(handle);
+    free_Buffer(b);
+    return JS_TRUE;
+  }
+
+  /* Shrink the buffer to the real size */
+  shrink_Buffer(b);
+
+  BufferToJSVal(context,b,rval);
+  
+  if(rval == NULL) {
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  JS_MaybeGC(context);
+
+  curl_easy_cleanup(handle);
+
+  return JS_TRUE;
+}
+
+static JSBool
+CopyHttp(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+  Buffer b;
+  char *url;
+  size_t charslen, readlen;
+  char header_name[5];
+  strcpy(header_name,"COPY");
+
+  // Run GC
+  JS_MaybeGC(context);
+
+  // Get URL
+  url = JSValToChar(context,argv);
+
+  // Allocate buffer that will store the del resultant
+  b = init_Buffer();
+
+  CURL* handle;
+
+  // Init Curl
+  if((handle = curl_easy_init()) == NULL) {
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+
+  // Configuration
+  curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEDATA,b);
+  curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEHEADER,b);
+  curl_easy_setopt(handle,CURLOPT_URL,url);
+  curl_easy_setopt(handle,CURLOPT_CUSTOMREQUEST,header_name);
+  curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
+  curl_easy_setopt(handle,CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4);
+
+  // Curl structure
+  struct curl_slist *slist = NULL;
+  if((slist = generateCurlHeaders(context,argv+1)) != NULL) {
+    curl_easy_setopt(handle,CURLOPT_HTTPHEADER,slist);
+  }
+
+  // Perform
+  int exitcode;
+
+  if((exitcode = curl_easy_perform(handle)) != 0) {
+    if(slist != NULL)
+      curl_slist_free_all(slist);
+    curl_easy_cleanup(handle);
+    free(url);
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+
+  if(slist != NULL)
+    curl_slist_free_all(slist);
+  free(url);
+
+  /* Treat the empty string specially */
+  if (b->count == 0) {
+    *rval = JS_GetEmptyStringValue(context);
+    curl_easy_cleanup(handle);
+    free_Buffer(b);
+    return JS_TRUE;
+  }
+
+  /* Shrink the buffer to the real size */
+  shrink_Buffer(b);
+
+  BufferToJSVal(context,b,rval);
+  
+  if(rval == NULL) {
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  JS_MaybeGC(context);
+
+  curl_easy_cleanup(handle);
+
+  return JS_TRUE;
+}
+
+static JSBool
+MoveHttp(JSContext *context, JSObject *obj, uintN argc, jsval *argv, jsval *rval) {
+  Buffer b;
+  char *url;
+  size_t charslen, readlen;
+  char header_name[5];
+  strcpy(header_name,"MOVE");
+
+  // Run GC
+  JS_MaybeGC(context);
+
+  // Get URL
+  url = JSValToChar(context,argv);
+
+  // Allocate buffer that will store the del resultant
+  b = init_Buffer();
+
+  CURL* handle;
+
+  // Init Curl
+  if((handle = curl_easy_init()) == NULL) {
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+
+  // Configuration
+  curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEDATA,b);
+  curl_easy_setopt(handle,CURLOPT_HEADERFUNCTION,curl_write);
+  curl_easy_setopt(handle,CURLOPT_WRITEHEADER,b);
+  curl_easy_setopt(handle,CURLOPT_URL,url);
+  curl_easy_setopt(handle,CURLOPT_CUSTOMREQUEST,header_name);
+  curl_easy_setopt(handle,CURLOPT_NOPROGRESS,1);
+  curl_easy_setopt(handle,CURLOPT_IPRESOLVE,CURL_IPRESOLVE_V4);
+
+  // Curl structure
+  struct curl_slist *slist = NULL;
+  if((slist = generateCurlHeaders(context,argv+1)) != NULL) {
+    curl_easy_setopt(handle,CURLOPT_HTTPHEADER,slist);
+  }
+
+  // Perform
+  int exitcode;
+
+  if((exitcode = curl_easy_perform(handle)) != 0) {
+    if(slist != NULL)
+      curl_slist_free_all(slist);
+    curl_easy_cleanup(handle);
+    free(url);
+    free_Buffer(b);
+    return JS_FALSE;
+  }
+
+  if(slist != NULL)
+    curl_slist_free_all(slist);
+  free(url);
+
+  /* Treat the empty string specially */
+  if (b->count == 0) {
+    *rval = JS_GetEmptyStringValue(context);
+    curl_easy_cleanup(handle);
+    free_Buffer(b);
+    return JS_TRUE;
+  }
+
+  /* Shrink the buffer to the real size */
+  shrink_Buffer(b);
+
+  BufferToJSVal(context,b,rval);
+  
+  if(rval == NULL) {
+    curl_easy_cleanup(handle);
+    return JS_FALSE;
+  }
+
+  JS_MaybeGC(context);
+
+  curl_easy_cleanup(handle);
+
+  return JS_TRUE;
+}
+
 int
 main(int argc, const char * argv[]) {
     JSRuntime *runtime;
@@ -428,7 +1215,14 @@
      || !JS_DefineFunction(context, global, "print", Print, 0, 0)
      || !JS_DefineFunction(context, global, "quit", Quit, 0, 0)
      || !JS_DefineFunction(context, global, "readline", ReadLine, 0, 0)
-     || !JS_DefineFunction(context, global, "seal", Seal, 0, 0))
+     || !JS_DefineFunction(context, global, "seal", Seal, 0, 0)
+     || !JS_DefineFunction(context, global, "gethttp", GetHttp, 1, 0)
+     || !JS_DefineFunction(context, global, "headhttp", HeadHttp, 1, 0)
+     || !JS_DefineFunction(context, global, "posthttp", PostHttp, 2, 0)
+     || !JS_DefineFunction(context, global, "puthttp", PutHttp, 2, 0)
+     || !JS_DefineFunction(context, global, "delhttp", DelHttp, 1, 0)
+     || !JS_DefineFunction(context, global, "movehttp", MoveHttp, 1, 0)
+     || !JS_DefineFunction(context, global, "copyhttp", CopyHttp, 1, 0))
         return 1;
 
     if (argc != 2) {

Added: incubator/couchdb/trunk/src/couchdb/curlhelper.c
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/couchdb/curlhelper.c?rev=703276&view=auto
==============================================================================
--- incubator/couchdb/trunk/src/couchdb/curlhelper.c (added)
+++ incubator/couchdb/trunk/src/couchdb/curlhelper.c Thu Oct  9 15:04:46 2008
@@ -0,0 +1,261 @@
+/*
+
+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 "curlhelper.h"
+
+#define TRUE 1
+#define FALSE 0
+
+Buffer init_Buffer() {
+  Buffer b;
+
+  if((b = (Buffer)malloc(sizeof(char*) + sizeof(int)*2)) == NULL) {
+    return NULL;
+  }
+
+  b->count = 0;
+  b->capacity = 50;
+
+  if(b->data = (char*)malloc(sizeof(char)*b->capacity)) {
+    return b;
+  } else {
+    return NULL;
+  }
+}
+
+void free_Buffer(Buffer b) {
+  if(b == NULL) 
+    return;
+  if(b->data != NULL)
+    free(b->data);
+  free(b);
+}
+
+int append_Buffer(Buffer b, char* c, int length) {
+  int capacity_changed;
+  int new_count;
+
+  capacity_changed = FALSE;
+  new_count = b->count + length;
+
+  if(new_count > b->capacity) {
+    capacity_changed = TRUE;
+    b->capacity *= 2;
+  }
+
+  while(new_count > b->capacity) {
+    b->capacity *= 2;
+  }
+
+  if(capacity_changed) {
+    if((b->data = (char*)realloc(b->data,b->capacity)) == NULL) {
+      return FALSE;
+    }
+  }
+
+  int i;
+
+  for(i = 0;i < length;i++) {
+    *(b->data + b->count + i) = *(c + i);
+  }
+
+  b->count = new_count;
+
+  return TRUE;
+}
+
+char* toString_Buffer(Buffer b) {
+  char* result;
+
+  if((result = (char*)malloc(sizeof(char)*(b->count+1))) == NULL) {
+    return NULL;
+  }
+
+  result[b->count] = '\0';
+
+  int i;
+
+  for(i = 0;i < b->count;i++) {
+    result[i] = b->data[i];
+  }
+
+  return result;
+}
+
+int print_Buffer(Buffer b) {
+  char* c;
+
+  if((c = toString_Buffer(b)) == NULL) {
+    return FALSE;
+  }
+
+  printf("%s\n",c);
+
+  free(c);
+
+  return TRUE;
+}
+
+
+int shrink_Buffer(Buffer b) {
+  b->capacity = b->count;
+
+  if((b->data = realloc(b->data,sizeof(char)*b->capacity)) == NULL) {
+    return FALSE;
+  } else {
+    return TRUE;
+  }
+}
+
+void copy_Buffer(Buffer b, char* c, int pos, int length) {
+  if((pos + length) > b->count)
+    return;
+
+  int i;
+
+  for(i = 0; i < length;i++) {
+    *(c + i) = *(b->data + pos + i);
+  }
+}
+
+
+List init_List(int capacity) {
+  if(capacity < 5)
+    capacity = 5;
+
+  List l;
+
+  if((l = (List)malloc(sizeof(void**)+sizeof(int)*2)) == NULL) {
+    return NULL;
+  }
+
+  l->count = 0;
+  l->capacity = capacity;
+
+  if((l->elements = (void**)malloc(sizeof(void*)*l->capacity)) == NULL) {
+    return NULL;
+  }
+
+  return l;
+}
+
+void free_List(List l) {
+  if(l == NULL)
+    return;
+  if(l->elements != NULL)
+    free(l->elements);
+  free(l);
+}
+
+void* get_List(List l, int pos) {
+  if(pos > (l->count - 1)) {
+    return NULL;
+  }
+  return *(l->elements + pos);
+}
+
+void* pull_List(List l) {
+  void* r = *(l->elements);
+
+  int i;
+
+  for(i = 1; i < (l->count-1);i++) {
+    l->elements[i] = l->elements[i+1];
+  }
+  l->count -= 1;
+  return r;
+}
+
+int set_List(List l, int pos, void* ptr) {
+  if(pos > (l->count - 1)) {
+    return FALSE;
+  }
+
+  *(l->elements + pos) = ptr;
+   
+  return TRUE;
+}
+
+int append_List(List l, void* ptr, int length) {
+  int capacity_changed;
+  int new_count;
+
+  capacity_changed = FALSE;
+  new_count = l->count + length;
+
+  if(new_count > l->capacity) {
+    capacity_changed = TRUE;
+    l->capacity *= 2;
+  }
+
+  while(new_count > l->capacity) {
+    l->capacity *= 2;
+  }
+
+  if(capacity_changed) {
+    if((l->elements = (void*)realloc(l->elements,l->capacity)) == NULL) {
+      return FALSE;
+    }
+  }
+
+  int i;
+
+  for(i = 0;i < length;i++) {
+    *(l->elements + l->count + i) = ptr + i;
+  }
+
+  l->count = new_count;
+
+  return TRUE;
+}
+
+int push_List(List l, void* ptr, int length) {
+  int capacity_changed;
+  int new_count;
+
+  capacity_changed = FALSE;
+  new_count = l->count + length;
+
+  if(new_count > l->capacity) {
+    capacity_changed = TRUE;
+    l->capacity *= 2;
+  }
+
+  while(new_count > l->capacity) {
+    l->capacity *= 2;
+  }
+
+  if(capacity_changed) {
+    if((l->elements = (void*)realloc(l->elements,l->capacity)) == NULL) {
+      return FALSE;
+    }
+  }
+
+  int i;
+
+  for(i = 0;i < length;i++) {
+    *(l->elements + l->count + i) = *(l->elements + i);
+  }
+
+  for(i = 0;i < length;i++) {
+    *(l->elements + i) = ptr+i;
+  }
+
+  l->count = new_count;
+
+  return TRUE;
+}

Propchange: incubator/couchdb/trunk/src/couchdb/curlhelper.c
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/couchdb/trunk/src/couchdb/curlhelper.h
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/couchdb/curlhelper.h?rev=703276&view=auto
==============================================================================
--- incubator/couchdb/trunk/src/couchdb/curlhelper.h (added)
+++ incubator/couchdb/trunk/src/couchdb/curlhelper.h Thu Oct  9 15:04:46 2008
@@ -0,0 +1,49 @@
+/*
+
+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 CURLHELPER_H
+#define CURLHELPER_H
+
+typedef struct {
+  char* data;
+  int count;
+  int capacity;
+}* Buffer;
+
+Buffer init_Buffer();
+void free_Buffer(Buffer b);
+int append_Buffer(Buffer b,char* c,int length);
+// WARNING USES MALLOC DONT FORGET TO FREE
+char* toString_Buffer(Buffer b);
+int print_Buffer(Buffer b);
+int shrink_Buffer(Buffer b);
+void copy_Buffer(Buffer b, char* c, int pos, int length);
+
+
+typedef struct {
+  void** elements;
+  int count;
+  int capacity;
+}* List;
+
+List init_List(int capacity);
+void free_List(List l);
+void* get_List(List l, int pos);
+void* pull_List(List l);
+int set_List(List l, int pos, void* ptr);
+int append_List(List l, void* ptr, int length);
+int push_List(List l, void* ptr, int length);
+
+#endif

Propchange: incubator/couchdb/trunk/src/couchdb/curlhelper.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/couchdb/trunk/test/runner.sh
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/test/runner.sh?rev=703276&r1=703275&r2=703276&view=diff
==============================================================================
--- incubator/couchdb/trunk/test/runner.sh (original)
+++ incubator/couchdb/trunk/test/runner.sh Thu Oct  9 15:04:46 2008
@@ -1,3 +1,5 @@
 #!/bin/sh -e
 
 erl -noshell -pa ../src/couchdb -pa ../src/mochiweb -eval "runner:run()"
+
+cat ../share/www/script/couch.js ../share/www/script/couch_tests.js test.js  | ../src/couchdb/couchjs
-

Added: incubator/couchdb/trunk/test/test.js
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/test/test.js?rev=703276&view=auto
==============================================================================
--- incubator/couchdb/trunk/test/test.js (added)
+++ incubator/couchdb/trunk/test/test.js Thu Oct  9 15:04:46 2008
@@ -0,0 +1,252 @@
+// 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.
+
+// couch.js, with modifications
+
+// 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.
+
+// some monkeypatches
+var JSON = {
+  parse : function(string) {
+    return eval('('+string+')');
+  },
+  stringify : function(obj) {
+    return toJSON(obj||null);
+  }
+};
+
+RegExp.escape = function(text) {
+  if (!arguments.callee.sRE) {
+    var specials = [
+      '/', '.', '*', '+', '?', '|',
+      '(', ')', '[', ']', '{', '}', '\\'
+    ];
+    arguments.callee.sRE = new RegExp(
+      '(\\' + specials.join('|\\') + ')', 'g'
+    );
+  }
+  return text.replace(arguments.callee.sRE, '\\$1');
+}
+
+// This is a JS wrapper for the curl function made available in couch_js.c,
+// it should be used in other JavaScripts that would like to make HTTP calls.
+
+var HTTP = (function() {
+  function parseCurl(string) {
+    var parts = string.split(/\r\n\r\n/);
+    var body = parts.pop();
+    var header = parts.pop();
+    var headers = header.split(/\n/);
+    
+    var status = /HTTP\/1.\d (\d*)/.exec(header)[1];
+    return {
+      responseText: body,
+      status: parseInt(status),
+      getResponseHeader: function(key) {
+        var keymatcher = new RegExp(RegExp.escape(key), "i");
+        for (var i in headers) {
+          var h = headers[i];
+          if (keymatcher.test(h)) {
+            var value = h.substr(key.length+2);
+            value = value.slice(0, value.length-1);
+            return value;
+          }
+        }
+        return "";
+      }
+    }
+  };
+  return {
+    GET : function(url, body, headers) {
+      var st, urx = url, hx = (headers || null);
+      st = gethttp(urx, hx);
+      return parseCurl(st);
+    },
+    HEAD : function(url, body, headers) {
+      var st, urx = url, hx = (headers || null);
+      st = headhttp(urx, hx);
+      return parseCurl(st);      
+    },
+    DELETE : function(url, body, headers) {
+      var st, urx = url, hx = (headers || null);
+      st = delhttp(urx, hx);
+      return parseCurl(st);
+    },
+    MOVE : function(url, body, headers) {
+      var st, urx = url, hx = (headers || null);
+      st = movehttp(urx, hx);
+      return parseCurl(st);
+    },
+    COPY : function(url, body, headers) {
+      var st, urx = url, hx = (headers || null);
+      st = copyhttp(urx, hx);
+      return parseCurl(st);
+    },
+    POST : function(url, body, headers) {
+      var st, urx = url, bx = (body || ""), hx = (headers || {});
+      hx['Content-Type'] = hx['Content-Type'] || "application/json";
+      st = posthttp(urx, bx, hx);
+      return parseCurl(st);
+    },
+    PUT : function(url, body, headers) {
+      var st, urx = url, bx = (body || ""), hx = (headers || {});
+      hx['Content-Type'] = hx['Content-Type'] || "application/json";
+      st = puthttp(urx, bx, hx);
+      return parseCurl(st);
+    }
+  };
+})();
+
+// Monkeypatches to CouchDB client for use of curl.
+
+CouchDB.host = (typeof window == 'undefined' || !window) ? "127.0.0.1" : window;
+CouchDB.port = 5984;
+
+CouchDB.request = function(method, uri, options) {
+  var full_uri = "http://" + CouchDB.host + ":" + CouchDB.port + uri;
+  options = options || {};
+  var response = HTTP[method](full_uri, options.body, options.headers);
+  return response;
+}
+
+
+function toJSON(val) {
+  if (typeof(val) == "undefined") {
+    throw {error:"bad_value", reason:"Cannot encode 'undefined' value as JSON"};
+  }
+  var subs = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f',
+              '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
+  if (typeof(val) == "xml") { // E4X support
+    val = val.toXMLString();
+  }
+  return {
+    "Array": function(v) {
+      var buf = [];
+      for (var i = 0; i < v.length; i++) {
+        buf.push(toJSON(v[i]));
+      }
+      return "[" + buf.join(",") + "]";
+    },
+    "Boolean": function(v) {
+      return v.toString();
+    },
+    "Date": function(v) {
+      var f = function(n) { return n < 10 ? '0' + n : n }
+      return '"' + v.getUTCFullYear()   + '-' +
+                 f(v.getUTCMonth() + 1) + '-' +
+                 f(v.getUTCDate())      + 'T' +
+                 f(v.getUTCHours())     + ':' +
+                 f(v.getUTCMinutes())   + ':' +
+                 f(v.getUTCSeconds())   + 'Z"';
+    },
+    "Number": function(v) {
+      return isFinite(v) ? v.toString() : "null";
+    },
+    "Object": function(v) {
+      if (v === null) return "null";
+      var buf = [];
+      for (var k in v) {
+        if (!v.hasOwnProperty(k) || typeof(k) !== "string" || v[k] === undefined) {
+          continue;
+        }
+        buf.push(toJSON(k, val) + ": " + toJSON(v[k]));
+      }
+      return "{" + buf.join(",") + "}";
+    },
+    "String": function(v) {
+      if (/["\\\x00-\x1f]/.test(v)) {
+        v = v.replace(/([\x00-\x1f\\"])/g, function(a, b) {
+          var c = subs[b];
+          if (c) return c;
+          c = b.charCodeAt();
+          return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
+        });
+      }
+      return '"' + v + '"';
+    }
+  }[val != null ? val.constructor.name : "Object"](val);
+}
+
+
+
+// *************** Test Framework Console Adapter ****************** //
+
+var p = print;
+var numFailures = 0;
+
+function runAllTestsConsole() {
+  var numTests = 0;
+  var debug = false;
+  for (var t in tests) {
+    p(t);
+    if (t == "utf8") {
+      p("We skip the utf8 test because it fails due to problems in couch_js.c");
+      p("Run the in-browser tests to verify utf8.\n");
+    } else {
+      numTests += 1;
+      var testFun = tests[t];
+      runTestConsole(testFun, debug);      
+    }
+  }
+  p("Results: "+numFailures.toString() + " failures in "+numTests+" tests.")
+};
+
+function runTestConsole(testFun, debug) {
+  var start = new Date().getTime();
+  try {
+    if (!debug) testFun = patchTest(testFun) || testFun;
+    testFun();
+    p("PASS");
+  } catch(e) {
+    p("ERROR");
+    p("Exception raised: "+e.toString());
+    p("Backtrace: "+e.stack);
+  }
+  var duration = new Date().getTime() - start;
+  p(duration+"ms\n");
+};
+
+
+// Use T to perform a test that returns false on failure and if the test fails,
+// display the line that failed.
+// Example:
+// T(MyValue==1);
+function T(arg1, arg2) {
+  if (!arg1) {
+    p("Assertion failed: "+(arg2 != null ? arg2 : arg1).toString());
+    numFailures += 1
+  }
+}
+
+p("Running CouchDB Test Suite\n");
+p("Host: "+CouchDB.host);
+p("Port: "+CouchDB.port);
+
+try {
+  p("Version: "+CouchDB.getVersion()+"\n");
+  runAllTestsConsole();
+  // runTestConsole(tests.attachments);
+} catch (e) {
+  p(e.toString());
+}
+
+p("\nFinished");

Propchange: incubator/couchdb/trunk/test/test.js
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message