Fork me on GitHub wwwdude

wwwdude

wwwdude is a small and flexible http client library on top of node\'s http client

index

lib//wwwdude/index.js

Module dependencies

var Url = require('url');
var EventEmitter = require('events').EventEmitter;
var Child_process = require('child_process');

var Util = require('./util');
var statusCodes = Util.codes;
var nodeVersion = process.version.slice(0, 6).replace(/\d$/, 'x');
var NodeWrapper = require('./node-versions/' + nodeVersion);

var defaultHeaders = {
  'User-Agent': 'node-wwwdude'
};

exports.version = '0.0.7';
exports.parsers = require('./parsers');

Factory method to create a client

  • return: Object

  • api: public

var createClient = exports.createClient = function createClient(clientOptions) {
  clientOptions = clientOptions || {};

  var encoding = clientOptions.encoding || 'utf8';
  var clientHeaders = Util.mergeHeaders(defaultHeaders, clientOptions.headers);

  if (clientOptions.gzip) {
    clientHeaders['Accept-Encoding'] = 'gzip';
  }

return the actual API

return {

HTTP GET request

  • param: String url

  • param: Object opts

  • return: EventEmitter

  • api: public

get: function get(url, opts) {
      opts = opts || {};
      opts.headers = Util.mergeHeaders(clientHeaders, opts.headers);
      return makeRequest('GET', url, opts);
    },

HTTP PUT request

  • param: String url

  • param: Object opts

  • return: EventEmitter

  • api: public

put: function put(url, opts) {
      opts = opts || {};
      opts.headers = Util.mergeHeaders(clientHeaders, opts.headers);
      return makeRequest('PUT', url, opts);
    },

HTTP POST request

  • param: String url

  • param: Object opts

  • return: EventEmitter

  • api: public

post: function post(url, opts) {
      opts = opts || {};
      opts.headers = Util.mergeHeaders(clientHeaders, opts.headers);
      return makeRequest('POST', url, opts);
    },

HTTP DELETE request

  • param: String url

  • param: Object opts

  • return: EventEmitter

  • api: public

del: function del(url, opts) {
      opts = opts || {};
      opts.headers = Util.mergeHeaders(clientHeaders, opts.headers);
      return makeRequest('DELETE', url, opts);
    },

HTTP DELETE request

  • param: String url

  • param: Object opts

  • return: Object client

  • return: EventEmitter

  • api: public

head: function head(url, opts) {
      opts = opts || {};
      opts.headers = Util.mergeHeaders(clientHeaders, opts.headers);
      return makeRequest('HEAD', url, opts);
    }

  };

};

v0.2.x

lib//wwwdude/node-versions/v0.2.x.js

Module dependencies

var Http = require('http');

Make the actual request for Node v0.2.x

  • param: Object context

  • return: undefined

  • api: public

exports.request = function (context) {
  var url = context.url;
  var headers = context.options.headers;
  var payload = context.options.payload;

  var client = Http.createClient(url.port, url.hostname);
  var request;

  headers.host = url.host;

  if (payload) {
    if (!headers['Content-Type']) {
      headers['Content-Type'] = 'application/x-www-form-urlencoded';
    }
    headers['Content-Length'] = Buffer.byteLength(payload);
    request = client.request(context.method, url.path, headers);
    request.write(payload, context.encoding);
  } else {
    request = client.request(context.method, url.path, headers);
  }

  client.on('error', function (err) {
      context.respond('error', err);
    });

  request.on('response', context.handler);
  request.end();
};

v0.4.x

lib//wwwdude/node-versions/v0.4.x.js

Module dependencies

var Http = require('http');
var Https = require('https');

Make the actual request for Node v0.4.x

  • param: Object context

  • return: undefined

  • api: public

exports.request = function (context) {
  var url = context.url;
  var headers = context.options.headers;
  var payload = context.options.payload;
  var request;

  var options = {
    host: url.hostname,
    port: url.port,
    path: url.path,
    method: context.method,
    headers: headers
  };

  if (payload) {
    if (!headers['Content-Type']) {
      headers['Content-Type'] = 'application/x-www-form-urlencoded';
    }
    headers['Content-Length'] = Buffer.byteLength(payload);
  }

  if (url.protocol === 'https:') {
    request = Https.request(options, context.handler);
  } else {
    request = Http.request(options, context.handler);
  }

  request.on('error', function (err) {
      context.respond('error', err);
    });

  if (payload) {
    request.write(payload);
  }

  request.end();
};

v0.5.x

lib//wwwdude/node-versions/v0.5.x.js

delegate requests to v0.4.x module

module.exports = require(__dirname + '/v0.4.x');

parsers

lib//wwwdude/parsers.js

Dependencies

var Util = require('util');

Content parser wrappers

  • return: Object

module.exports = {

  json: function json(content, callback) {
    try {
      if (content) {
        var parsed = JSON.parse(content);
        callback(null, parsed);
      } else {
        callback(null, {});
      }
    } catch (err) {
      callback(err);
    }
  },

  xml: function xml(content, callback) {
    var Xml2Js = require('xml2js-expat');
    var xmlParser = new Xml2Js.Parser(function (result, error) {
        if (error) {
          callback(error);
        } else {
          callback(null, result);
        }
      });
    xmlParser.parseString(content);
  }

};

util

lib//wwwdude/util.js

Module dependencies

var Url = require('url');

lookup table for all HTTP status codes

  • api: public

exports.codes = {

1XX Informational

//'100': 'continue',
  //'101': 'switching-protocols',

2XX Successful

'200': 'ok',
  '201': 'created',
  '202': 'accepted',
  '203': 'non-authorative-information',
  '204': 'no-content',
  '205': 'reset-content',
  '207': 'partial-content',

3XX Redirection

'300': 'multiple-choices',
  '301': 'moved-permanently',
  '302': 'found',
  '303': 'see-other',
  '304': 'not-modified',
  '305': 'use-proxy',
  '307': 'temporary-redirect',

4XX Client Error

'400': 'bad-request',
  '401': 'unauthorized',
  '402': 'payment-required',
  '403': 'forbidden',
  '404': 'not-found',
  '405': 'method-not-allowed',
  '406': 'not-acceptable',
  '407': 'proxy-authentication-required',
  '408': 'request-timeout',
  '409': 'conflict',
  '410': 'gone',
  '411': 'length-required',
  '412': 'precondition-failed',
  '413': 'request-entity-too-large',
  '414': 'request-uri-too-long',
  '415': 'unsupported-media-type',
  '416': 'request-range-not-satisfiable',
  '417': 'expectation-failed',

5XX Server Error

'500': 'internal-server-error',
  '501': 'not-implemented',
  '502': 'bad-gateway',
  '503': 'service-unavailable',
  '504': 'gateway-timeout',
  '505': 'http-version-not-supported'
};

Take two objects and merge their attributes

  • param: Object defaults

  • param: Object custom

  • return: Object new merged object

  • api: public

var mergeHeaders = exports.mergeHeaders = function mergeHeaders(defaults, custom) {
  var obj = {};

  function _normalizeKeys(toMerge) {
    function _normalizeKey(key) {
      return key.split('-').map(function (part) {
          return part.charAt(0).toUpperCase() + part.substring(1);
        }).join('-');
    }

    Object.keys(toMerge).forEach(function (key) {
        var normKey = _normalizeKey(key);
        obj[normKey] = toMerge[key];
      });
  }

  _normalizeKeys(defaults);

  if (!custom) {
    return obj;
  }

  _normalizeKeys(custom);

  return obj;
};

Parse an URL an add some needed properties

  • param: String url

  • return: Object

  • api: public

exports.parseUrl = function parseUrl(url) {
  var parsedUrl = Url.parse(url);
  var container = {};

  container.port = parsedUrl.port || ((parsedUrl.protocol === 'https:') ? '443' : '80');
  container.queryparms = parsedUrl.query ? '?' + parsedUrl.query :  '';
  container.hash = parsedUrl.hash || '';
  container.path = (parsedUrl.pathname || '/') + container.queryparms + container.hash;
  container.host = parsedUrl.host;
  container.hostname = parsedUrl.hostname;
  container.protocol = parsedUrl.protocol;

  return container;
};