Skip to content
Browse files

first commit

  • Loading branch information...
0 parents commit 414d762dbc6128b75b316fb98aa0856c4503c403 @dhruvbird committed Jun 13, 2011
Showing with 440 additions and 0 deletions.
  1. +31 −0 README.md
  2. +243 −0 curllib.cc
  3. +94 −0 http-sync.js
  4. +29 −0 test.js
  5. +28 −0 test_require.js
  6. +15 −0 wscript
31 README.md
@@ -0,0 +1,31 @@
+You will need:
+
+* node.js source code
+* v8 source code
+* libcurl development package
+
+Building:
+
+ node-waf configure && node-waf build
+
+Copy Generated library to current directory:
+
+ cp build/default/curllib.node .
+
+Run the test.js file:
+
+ node test.js
+
+Using:
+
+```javascript
+// Test GET request
+var req = http_sync.request({
+ host: 'nodejs.org',
+ path: '/'
+});
+
+var res = req.end();
+console.log(res);
+console.log(res.body.toString());
+```
243 curllib.cc
@@ -0,0 +1,243 @@
+/* This code is PUBLIC DOMAIN, and is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND. See the accompanying
+ * LICENSE file.
+ */
+
+#include <v8.h>
+#include <node.h>
+#include <node_buffer.h>
+#include <curl/curl.h>
+#include <string>
+#include <string.h>
+#include <vector>
+#include <stdint.h>
+#include <iostream>
+
+using namespace node;
+using namespace v8;
+
+#define THROW_BAD_ARGS \
+ ThrowException(Exception::TypeError(String::New("Bad argument")))
+
+typedef std::vector<char> buff_t;
+
+
+class CurlLib : ObjectWrap {
+private:
+ static std::string buffer;
+ static std::vector<std::string> headers;
+
+public:
+
+ static Persistent<FunctionTemplate> s_ct;
+ static void Init(Handle<Object> target) {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+
+ s_ct = Persistent<FunctionTemplate>::New(t);
+ s_ct->InstanceTemplate()->SetInternalFieldCount(1);
+ s_ct->SetClassName(String::NewSymbol("CurlLib"));
+
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "run", Run);
+ NODE_SET_PROTOTYPE_METHOD(s_ct, "body", Body);
+
+ target->Set(String::NewSymbol("CurlLib"),
+ s_ct->GetFunction());
+ }
+
+ CurlLib()
+ {
+ }
+
+ ~CurlLib()
+ {
+ }
+
+ static Handle<Value> New(const Arguments& args)
+ {
+ HandleScope scope;
+ CurlLib* curllib = new CurlLib();
+ curllib->Wrap(args.This());
+ return args.This();
+ }
+
+ static size_t read_data(void *ptr, size_t size, size_t nmemb, void *userdata) {
+ size_t len = size * nmemb;
+ buff_t *pin = (buff_t*)(userdata);
+
+ size_t to_write = (pin->size() > len ? len : pin->size());
+ if (to_write == 0) {
+ return 0;
+ }
+
+ memcpy(ptr, &*(pin->begin()), to_write);
+ pin->erase(pin->begin(), pin->begin() + to_write);
+ return to_write;
+ }
+
+ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *userdata)
+ {
+ buffer += std::string((char*)ptr, size*nmemb);
+ std::cerr<<"Wrote: "<<size*nmemb<<" bytes"<<std::endl;
+ std::cerr<<"Buffer size: "<<buffer.size()<<" bytes"<<std::endl;
+ return size * nmemb;
+ }
+
+ static size_t write_headers(void *ptr, size_t size, size_t nmemb, void *userdata)
+ {
+ std::string header((char*)ptr, size*nmemb);
+ headers.push_back(header);
+ return size * nmemb;
+ }
+
+ static void copy_to_buffer(buff_t &dest, Local<String> &src) {
+ std::cerr<<"copy_to_buffer::Length::"<<src->Length()<<std::endl;
+
+ if (src->Length() > 0) {
+ dest.resize(src->Length() + 1);
+ src->WriteAscii(&dest[0], 0, src->Length());
+ }
+ }
+
+ static Handle<Value> Body(const Arguments& args) {
+ if (args.Length() < 1 || !Buffer::HasInstance(args[0])) {
+ return THROW_BAD_ARGS;
+ }
+
+ HandleScope scope;
+ Local<Object> buffer_obj = args[0]->ToObject();
+ char *buffer_data = Buffer::Data(buffer_obj);
+ size_t buffer_length = Buffer::Length(buffer_obj);
+
+ if (buffer_length < buffer.size()) {
+ return ThrowException(Exception::TypeError(
+ String::New("Insufficient Buffer Length")));
+ }
+
+ if (!buffer.empty()) {
+ memcpy(buffer_data, &buffer[0], buffer.size());
+ }
+ buffer.clear();
+ return scope.Close(buffer_obj);
+ }
+
+ static Handle<Value> Run(const Arguments& args) {
+ if (args.Length() < 3 || !args[0]->IsString() || !args[1]->IsString() || !args[2]->IsArray()) {
+ return THROW_BAD_ARGS;
+ }
+
+ if (args.Length() > 3 && !args[3]->IsString()) {
+ return THROW_BAD_ARGS;
+ }
+
+ Local<String> method = args[0]->ToString();
+ Local<String> url = args[1]->ToString();
+ Local<Array> reqh = Local<Array>::Cast(args[2]);
+ Local<String> body = String::New((const char*)"", 0);
+
+ if (args.Length() > 3) {
+ body = args[3]->ToString();
+ }
+
+ buff_t _body, _method, _url;
+ std::vector<buff_t> _reqh;
+
+ copy_to_buffer(_body, body);
+ if (!_body.empty()) {
+ _body.resize(_body.size() - 1);
+ }
+
+ copy_to_buffer(_method, method);
+ copy_to_buffer(_url, url);
+
+ for (size_t i = 0; i < reqh->Length(); ++i) {
+ buff_t _tmp;
+ Local<String> _src = reqh->Get(i)->ToString();
+ copy_to_buffer(_tmp, _src);
+ _reqh.push_back(_tmp);
+ }
+
+ HandleScope scope;
+ CurlLib* curllib = ObjectWrap::Unwrap<CurlLib>(args.This());
+ // Local<String> result = String::New("Hello World");
+
+ buffer.clear();
+ headers.clear();
+
+ CURL *curl;
+ CURLcode res;
+
+ // char error_buffer[CURL_ERROR_SIZE];
+ // error_buffer[0] = '\0';
+
+ curl = curl_easy_init();
+ if(curl) {
+ // curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+ // curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer);
+
+ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, &_method[0]);
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_data);
+ curl_easy_setopt(curl, CURLOPT_READDATA, (void*)&_body);
+ curl_easy_setopt(curl, CURLOPT_URL, &_url[0]);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_headers);
+
+ // FIXME
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
+
+ struct curl_slist *slist = NULL;
+
+ for (size_t i = 0; i < _reqh.size(); ++i) {
+ slist = curl_slist_append(slist, &(_reqh[i][0]));
+ }
+
+ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
+
+ res = curl_easy_perform(curl);
+
+ curl_slist_free_all(slist);
+
+ /* always cleanup */
+ curl_easy_cleanup(curl);
+ }
+
+ // std::cerr<<"error_buffer: "<<error_buffer<<std::endl;
+
+ // Local<String> result = String::New("Hello World");
+ Local<Object> result = Object::New();
+
+ if (!res) {
+ result->Set(NODE_PSYMBOL("body_length"), Integer::New(buffer.size()));
+ Local<Array> _h = Array::New();
+ for (size_t i = 0; i < headers.size(); ++i) {
+ _h->Set(i, String::New(headers[i].c_str()));
+ }
+ result->Set(NODE_PSYMBOL("headers"), _h);
+ }
+ else {
+ result->Set(NODE_PSYMBOL("error"), String::New(curl_easy_strerror(res)));
+ }
+
+ // buffer.clear();
+ headers.clear();
+
+ return scope.Close(result);
+ }
+
+};
+
+Persistent<FunctionTemplate> CurlLib::s_ct;
+std::string CurlLib::buffer;
+std::vector<std::string> CurlLib::headers;
+
+
+extern "C" {
+ static void init (Handle<Object> target)
+ {
+ CurlLib::Init(target);
+ }
+
+ NODE_MODULE(curllib, init);
+}
94 http-sync.js
@@ -0,0 +1,94 @@
+var _cl = require('./curllib');
+var curllib = new _cl.CurlLib();
+
+// console.log("curlllib:", curllib);
+
+function CurlRequest(options) {
+ this._options = options;
+ this._headers = { };
+
+ var k;
+ for (k in this._options.headers) {
+ this.setHeader(k, _options.headers[k]);
+ }
+}
+
+CurlRequest.prototype = {
+ getHeader: function(name) {
+ return this._headers[name.toLowerCase()];
+ },
+ removeHeader: function(name) {
+ delete this._headers[name.toLowerCase()];
+ },
+ setHeader: function(name, value) {
+ this._headers[name.toLowerCase()] = value;
+ },
+ write: function(data) {
+ data = data || '';
+ this._options.body += data;
+ },
+ end: function(data) {
+ this.write(data);
+ var _ep = this._options.protocol + '://' + this._options.host +
+ ':' + this._options.port + this._options.path;
+ var _h = [ ];
+ var k;
+ for (k in this._headers) {
+ _h.push(k + ': ' + this._headers[k]);
+ }
+
+ var ret = curllib.run(this._options.method, _ep,
+ _h, this._options.body);
+
+ if (ret.error) {
+ throw new Error(ret.error);
+ }
+
+ ret.body = '';
+ if (ret.body_length) {
+ var _b = new Buffer(ret.body_length);
+ ret.body = curllib.body(_b);
+ }
+
+ function _parse_headers(headers) {
+ var _sre = /HTTP\/[0-9].[0-9] ([0-9]{3})/;
+ var _hre = /([^:]+):([\s]*)([^\r\n]*)/;
+ var statusCode = 200;
+ var _h = { };
+ headers.forEach(function(line) {
+ var _m = line.match(_sre);
+ if (_m) {
+ statusCode = _m[1];
+ }
+ else {
+ _m = line.match(_hre);
+ if (_m) {
+ _h[_m[1]] = _m[3];
+ }
+ }
+ });
+ return {
+ statusCode: statusCode,
+ headers: _h
+ };
+ }
+
+ var _ph = _parse_headers(ret.headers);
+ ret.statusCode = _ph.statusCode;
+ ret.headers = _ph.headers;
+
+ return ret;
+ }
+};
+
+exports.request = function(options) {
+ options.protocol = options.protocol || 'http';
+ options.port = options.port || (options.protocol === 'https' ? 443 : 80);
+ options.method = options.method || 'GET';
+ options.path = options.path || '/';
+ options.headers = options.headers || { };
+ options.host = options.host || '127.0.0.1';
+ options.body = options.body || '';
+
+ return new CurlRequest(options);
+};
29 test.js
@@ -0,0 +1,29 @@
+var http_sync = require('./http-sync')
+
+
+// Test GET request
+var req = http_sync.request({
+ host: 'nodejs.org',
+ path: '/'
+});
+
+// console.log(req);
+
+var res = req.end();
+console.log(res);
+console.log(res.body.toString());
+
+
+// Test POST request
+req = http_sync.request({
+ protocol: 'https',
+ method: 'POST',
+ host: 'talk.to',
+ path: '/bosh/http-bind/',
+ body: '<body/>'
+});
+
+res = req.end();
+console.log(res);
+console.log(res.body.toString());
+
28 test_require.js
@@ -0,0 +1,28 @@
+
+function remote_require(_url) {
+ var http_sync = require('./http-sync')
+ var url = require('url');
+ var fs = require('fs');
+
+ var _u = url.parse(_url);
+
+ var req = http_sync.request({
+ host: _u.hostname,
+ port: _u.port,
+ path: _u.pathname
+ });
+
+ var res = req.end();
+ // console.log(res);
+ // console.log(res.body.toString());
+ var _fname = '/tmp/some_random_name_that_changes_every_time.js';
+ fs.writeFileSync(_fname, res.body.toString());
+ return require(_fname);
+}
+
+// Fetch underscore.js
+var _ = remote_require('http://documentcloud.github.com/underscore/underscore-min.js');
+// console.log(_);
+
+// Do something with _
+console.log(_([1,2,3,4]).map(function(x) { return x*x; }));
15 wscript
@@ -0,0 +1,15 @@
+
+def set_options(opt):
+ opt.tool_options("compiler_cxx")
+
+def configure(conf):
+ conf.check_tool("compiler_cxx")
+ conf.check_tool("node_addon")
+ conf.check_cfg(package='libcurl', args='--cflags --libs "libcurl"')
+
+def build(bld):
+ obj = bld.new_task_gen("cxx", "shlib", "node_addon")
+ obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
+ obj.target = "curllib"
+ obj.source = "curllib.cc"
+ obj.lib = ["curl"]

0 comments on commit 414d762

Please sign in to comment.
Something went wrong with that request. Please try again.