New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

shred

Package Overview
Dependencies
Maintainers
1
Versions
54
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

shred - npm Package Compare versions

Comparing version 0.5.5 to 0.6.0

docs/content.html

34

lib/shred.js

@@ -0,9 +1,14 @@

// Shred is an HTTP client library intended to simplify the use of Node's
// built-in HTTP library. In particular, we wanted to make it easier to interact
// with HTTP-based APIs.
//
// See the [examples](./examples.html) for more details.
var _ = require("underscore")
// Ax is a nice logging library we wrote. You can use any logger, providing it
// has `info`, `warn`, `debug`, and `error` methods that take a string.
, Ax = require("ax")
;
var Modules = {
Request: require("./shred/request"),
Response: require("./shred/response")
}
// Shred takes some options, including a logger and request defaults.

@@ -16,12 +21,22 @@ var Shred = function(options) {

_.extend(Shred, Modules);
// Most of the real work is done in the request and reponse classes.
Shred.Request = require("./shred/request");
Shred.Response = require("./shred/response");
var Methods = {
// The `request` method kicks off a new request, instantiating a new `Request`
// object and passing along whatever default options we were given.
Shred.prototype = {
request: function(options) {
return new Shred.Request(this, _.defaults(options,this.defaults));
options.logger = this.log;
return new Shred.Request(_.defaults(options,this.defaults));
}
};
"GET PUT POST DELETE".split(" ").forEach(function(method) {
Methods[method] = Methods[method.toLowerCase(method)] = function(options) {
// Define a bunch of convenience methods so that you don't have to include
// a `method` property in your request options.
"get put post delete".split(" ").forEach(function(method) {
Shred.prototype[method] = function(options) {
options.method = method;

@@ -32,4 +47,3 @@ return this.request(options);

_.extend(Shred.prototype, Methods);
module.exports = Shred;
var _ = require("underscore");
// The purpose of the `Content` object is to abstract away the data conversions
// to and from raw content entities as strings. For example, you want to be able
// to pass in a Javascript object and have it be automatically converted into a
// JSON string if the `content-type` is set to a JSON-based media type.
// Conversely, you want to be able to transparently get back a Javascript object
// in the response if the `content-type` is a JSON-based media-type.
// One limitation of the current implementation is that it [assumes the `charset` is UTF-8](https://github.com/spire-io/shred/issues/5).
// The `Content` constructor takes an options object, which *must* have either a
// `body` or `data` property and *may* have a `type` property indicating the
// media type. If there is no `type` attribute, a default will be inferred.
var Content = function(options) {

@@ -10,6 +22,17 @@ this.body = options.body;

Content.prototype = {
//toString: function() { return this.body; }
// Treat `toString()` as asking for the `content.body`. That is, the raw content entity.
//
// toString: function() { return this.body; }
//
// Commented out, but I've forgotten why. :/
};
// `Content` objects have the following attributes:
Object.defineProperties(Content.prototype,{
// - **type**. Typically accessed as `content.type`, reflects the `content-type`
// header associated with the request or response. If not passed as an options
// to the constructor or set explicitly, it will infer the type the `data`
// attribute, if possible, and, failing that, will default to `text/plain`.
type: {

@@ -35,2 +58,9 @@ get: function() {

},
// - **data**. Typically accessed as `content.data`, reflects the content entity
// converted into Javascript data. This can be a string, if the `type` is, say,
// `text/plain`, but can also be a Javascript object. The conversion applied is
// based on the `processor` attribute. The `data` attribute can also be set
// directly, in which case the conversion will be done the other way, to infer
// the `body` attribute.
data: {

@@ -51,2 +81,7 @@ get: function() {

},
// - **body**. Typically accessed as `content.body`, reflects the content entity
// as a UTF-8 string. It is the mirror of the `data` attribute. If you set the
// `data` attribute, the `body` attribute will be inferred and vice-versa. If
// you attempt to set both, an exception is raised.
body: {

@@ -67,2 +102,8 @@ get: function() {

},
// - **processor**. The functions that will be used to convert to/from `data` and
// `body` attributes. You can add processors. The two that are built-in are for
// `text/plain`, which is basically an identity transformation and
// `application/json` and other JSON-based media types (including custom media
// types with `+json`). You can add your own processors. See below.
processor: {

@@ -74,4 +115,4 @@ get: function() {

} else {
// return the first processor that matches any part of the
// content type. ex: application/vnd.foobar.baz+json will match json
// Return the first processor that matches any part of the
// content type. ex: application/vnd.foobar.baz+json will match json.
processor = _(this.type.split(";")[0]

@@ -87,2 +128,5 @@ .split(/\+|\//)).detect(function(type) {

},
// - **length**. Typically accessed as `content.length`, returns the length in
// bytes of the raw content entity.
length: {

@@ -95,3 +139,13 @@ get: function() { return this.body.length; }

// The `registerProcessor` function allows you to add your own processors to
// convert content entities. Each processor consists of a Javascript object with
// two properties:
// - **parser**. The function used to parse a raw content entity and convert it
// into a Javascript data type.
// - **stringify**. The function used to convert a Javascript data type into a
// raw content entity.
Content.registerProcessor = function(types,processor) {
// You can pass an array of types that will trigger this processor, or just one.
// We determine the array via duck-typing here.
if (types.forEach) {

@@ -102,3 +156,3 @@ types.forEach(function(type) {

} else {
// 'types' is actually just one type
// If you didn't pass an array, we just use what you pass in.
Content.processors[types] = processor;

@@ -108,2 +162,3 @@ }

// Register the identity processor, which is used for text-based media types.
var identity = function(x) { return x; }

@@ -115,2 +170,3 @@ , toString = function(x) { return x.toString(); }

// Register the JSON processor, which is used for JSON-based media types.
Content.registerProcessor(

@@ -125,2 +181,4 @@ ["application/json; charset=utf-8","application/json","json"],

// Error functions are defined separately here in an attempt to make the code
// easier to read.
var Errors = {

@@ -127,0 +185,0 @@ setDataWithBody: function(object) {

@@ -1,8 +0,22 @@

// One of the reasons we're defining the implementation here using private
// methods is so that clients can use call or apply with one mixin without
// introducing a dependency on another (ex: Getters without Setters)
// The header mixins allow you to add HTTP header support to any object. This
// might seem pointless: why not simply use a hash? The main reason is that, per
// the [HTTP spec](http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2),
// headers are case-insensitive. So, for example, `content-type` is the same as
// `CONTENT-TYPE` which is the same as `Content-Type`. Since there is no way to
// overload the index operator in Javascript, using a hash to represent the
// headers means it's possible to have two conflicting values for a single
// header.
//
// The solution to this is to provide explicit methods to set or get headers.
// This also has the benefit of allowing us to introduce additional variations,
// including snake case, which we automatically convert to what Matthew King has
// dubbed "corset case" - the hyphen-separated names with initial caps:
// `Content-Type`. We use corset-case just in case we're dealing with servers
// that haven't properly implemented the spec.
var _ = require("underscore")
;
// Convert headers to corset-case. **Example:** `CONTENT-TYPE` will be converted
// to `Content-Type`.
var corsetCase = function(string) {

@@ -15,2 +29,3 @@ return string.toLowerCase()

// We suspect that `initializeHeaders` was once more complicated ...
var initializeHeaders = function(object) {

@@ -20,2 +35,5 @@ return {};

// Access the `_headers` property using lazy initialization. **Warning:** If you
// mix this into an object that is using the `_headers` property already, you're
// going to have trouble.
var $H = function(object) {

@@ -25,2 +43,5 @@ return object._headers||(object._headers=initializeHeaders(object));

// Hide the implementations as private functions, separate from how we expose them.
// The "real" `getHeader` function: get the header after normalizing the name.
var getHeader = function(object,name) {

@@ -30,2 +51,4 @@ return $H(object)[corsetCase(name)];

// The "real" `getHeader` function: get one or more headers, or all of them
// if you don't ask for any specifics.
var getHeaders = function(object,names) {

@@ -37,2 +60,4 @@ var keys = (names && names.length>0) ? names : Object.keys($H(object));

},{});
// Freeze the resulting hash so you don't mistakenly think you're modifying
// the real headers.
Object.freeze(hash);

@@ -42,2 +67,3 @@ return hash;

// The "real" `setHeader` function: set a header, after normalizing the name.
var setHeader = function(object,name,value) {

@@ -48,2 +74,3 @@ $H(object)[corsetCase(name)] = value;

// The "real" `setHeaders` function: set multiple headers based on a hash.
var setHeaders = function(object,hash) {

@@ -54,30 +81,28 @@ for( var key in hash ) { setHeader(object,key,hash[key]); };

var Headers = {
Getters: {
Methods: {
getHeader: function(name) { return getHeader(this,name); },
getHeaders: function() { return getHeaders(this,_(arguments)); }
},
Properties: {},
mixWith: function(exemplar) { return mixin(exemplar,this); }
// Here's where we actually bind the functionality to an object. These mixins work by
// exposing mixin functions. Each function mixes in a specific batch of features.
module.exports = {
// Add getters.
getters: function(constructor) {
constructor.prototype.getHeader = function(name) { return getHeader(this,name); };
constructor.prototype.getHeaders = function() { return getHeaders(this,_(arguments)); };
},
Setters: {
Methods: {
setHeader: function(key,value) { return setHeader(this,key,value); },
setHeaders: function(hash) { return setHeaders(this,hash); }
},
Properties: {},
mixWith: function(exemplar) { return mixin(exemplar,this); }
// Add setters but as "private" methods.
privateSetters: function(constructor) {
constructor.prototype._setHeader = function(key,value) { return setHeader(this,key,value); };
constructor.prototype._setHeaders = function(hash) { return setHeaders(this,hash); };
},
};
var mixin = function(exemplar,mixin) {
for (var method in mixin.Methods) {
exemplar.prototype[method] = mixin.Methods[method];
}
Object.defineProperties(exemplar.prototype, mixin.Properties);
return exemplar;
};
module.exports = Headers;
// Add setters.
setters: function(constructor) {
constructor.prototype.setHeader = function(key,value) { return setHeader(this,key,value); };
constructor.prototype.setHeaders = function(hash) { return setHeaders(this,hash); };
},
// Add both getters and setters.
gettersAndSetters: function(constructor) {
constructor.prototype.getHeader = function(name) { return getHeader(this,name); };
constructor.prototype.getHeaders = function() { return getHeaders(this,_(arguments)); };
constructor.prototype.setHeader = function(key,value) { return setHeader(this,key,value); };
constructor.prototype.setHeaders = function(hash) { return setHeaders(this,hash); };
},
};

@@ -0,1 +1,4 @@

// The request object encapsulates a request, creating a Node.js HTTP request and
// then handling the response.
var HTTP = require("http")

@@ -13,15 +16,20 @@ , HTTPS = require("https")

var Request = function(client, options) {
// The Shred object itself constructs the `Request` object. You should rarely
// need to do this directly.
var Request = function(options) {
this.log = options.logger;
processOptions(this,options||{});
createRequest(this);
};
this.client = client;
this.log = client.log;
// A `Request` has a number of properties, many of which help with details like
// URL parsing or defaulting the port for the request.
Private.processOptions(this,options||{});
Private.createRequest(this);
Object.defineProperties(Request.prototype, {
};
// - **url**. You can set the `url` property with a valid URL string and all the
// URL-related properties (host, port, etc.) will be automatically set on the
// request object.
Object.defineProperties(Request.prototype, {
url: {

@@ -47,9 +55,19 @@ get: function() {

headers: {
get: function() { return this.getHeaders(); },
enumerable: true
// - **headers**. Returns a hash representing the request headers. You can't set
// this directly, only get it. You can add or modify headers by using the
// `setHeader` or `setHeaders` method. This ensures that the headers are
// normalized - that is, you don't accidentally send `Content-Type` and
// `content-type` headers. Keep in mind that if you modify the returned hash,
// it will *not* modify the request headers.
headers: {
get: function() {
return this.getHeaders();
},
enumerable: true
},
// port -
// defaults based on the scheme
// - **port**. Unless you set the `port` explicitly or include it in the URL, it
// will default based on the scheme.
port: {

@@ -69,4 +87,6 @@ get: function() {

},
// method
// default to GET
// - **method**. The request method - `get`, `put`, `post`, etc. that will be
// used to make the request. Defaults to `get`.
method: {

@@ -82,5 +102,6 @@ get: function() {

// query
// can be set with an object, which is converted to a query string
// get returns the query string
// - **query**. Can be set either with a query string or a hash (object). Get
// will always return a properly escaped query string or null if there is no
// query component for the request.
query: {

@@ -93,3 +114,3 @@ get: function() {return this._query;},

} else {
value = value.toString()
value = QueryString.stringify(QueryString.parse(value.toString()))
}

@@ -104,12 +125,15 @@ }

// parameters
// get only - returns the object representation of the query
// - **parameters**. This will return the query parameters in the form of a hash
// (object).
parameters: {
get: function() { return QueryString.parse(this._query); },
get: function() { return QueryString.parse(this._query||""); },
enumerable: true
},
// body
// set will automatically construct a Content object
// get returns the Content object
// - **content**. (Aliased as `body`.) Set this to add a content entity to the
// request. Attempts to use the `content-type` header to determine what to do
// with the content value. Get this to get back a [`Content`
// object](./content.html).
body: {

@@ -129,6 +153,8 @@ get: function() { return this._body; },

// timeout
// set will take either milliseconds or an object with
// temporal attributes (hours, minutes, seconds) and
// convert it into milliseconds
// - **timeout**. Used to determine how long to wait for a response. Does not
// distinguish between connect timeouts versus request timeouts. Set either in
// milliseconds or with an object with temporal attributes (hours, minutes,
// seconds) and convert it into milliseconds. Get will always return
// milliseconds.
timeout: {

@@ -155,7 +181,14 @@ get: function() { return this._timeout; }, // in milliseconds

// alias proprety: content to body
// Alias `body` property to `content`. Since the [content object](./content.html)
// has a `body` attribute, it's preferable to use `content` since you can then
// access the raw content data using `content.body`.
Object.defineProperty(Request.prototype,"content",
Object.getOwnPropertyDescriptor(Request.prototype, "body"));
// Methods
// The `Request` object can be pretty overwhelming to view using the built-in
// Node.js inspect method. We want to make it a bit more manageable. This
// probably goes [too far in the other
// direction](https://github.com/spire-io/shred/issues/2).
_.extend(Request.prototype,{

@@ -170,121 +203,164 @@ inspect: function() {

return [ summary, "- Headers:", headers].join("\n");
},
send: function() {
}
});
var Private = {
processOptions: function(request,options) {
// Add in the header methods. Again, these ensure we don't get the same header
// multiple times with different case conventions.
HeaderMixins.gettersAndSetters(Request);
request.log.debug("Processing request options ..");
// `processOptions` is called from the constructor to handle all the work
// associated with making sure we do our best to ensure we have a valid request.
request.emitter = (new Emitter);
if (options.on) {
_(options.on).each(function(value,key) {
request.emitter.on(key,value);
});
} else throw("No event handlers provided. Response will be unused.");
var processOptions = function(request,options) {
// Make sure we were give a URL or a host
if (!options.url && !options.host) {
request.emitter.emit("Error",
new Error("No url or url options (host, port, etc.)"));
}
request.log.debug("Processing request options ..");
if (options.url) {
if (options.proxy) {
request.url = options.proxy;
request.path = options.url;
} else {
request.url = options.url;
}
}
// We'll use `request.emitter` to manage the `on` event handlers.
request.emitter = (new Emitter);
// Set up the handlers ...
if (options.on) {
_(options.on).each(function(value,key) {
request.emitter.on(key,value);
});
// ... and let someone know if we didn't get any.
} else throw("No event handlers provided. Response will be unused.");
request.query = options.query||options.parameters;
request.method = options.method;
request.setHeader("User-Agent","Shred for Node.js, Version 0.1.0");
request.setHeaders(options.headers);
if (options.body||options.content) {
request.content = options.body||options.content;
// Make sure we were give a URL or a host
if (!options.url && !options.host) {
request.emitter.emit("error",
new Error("No url or url options (host, port, etc.)"));
return;
}
// Allow for the [use of a proxy](http://www.jmarshall.com/easy/http/#proxies).
if (options.url) {
if (options.proxy) {
request.url = options.proxy;
request.path = options.url;
} else {
request.url = options.url;
}
request.timeout = options.timeout;
}
},
createRequest: function(request) {
var timeout
, shred = request.client
;
// Set the remaining options.
request.query = options.query||options.parameters;
request.method = options.method;
request.setHeader("user-agent",options.agent||"Shred for Node.js, Version 0.5.0");
request.setHeaders(options.headers);
// The content entity can be set either using the `body` or `content` attributes.
if (options.body||options.content) {
request.content = options.body||options.content;
}
request.timeout = options.timeout;
request.log.debug("Creating request ..");
request.log.debug(request);
var http = request.scheme == "http" ? HTTP : HTTPS;
request._raw = http.request({
host: request.host,
port: request.port,
method: request.method,
path: request.path+request.query,
headers: request.getHeaders()
}, function(response) {
};
request.log.debug("Received response ..");
// `createRequest` is also called by the constructor, after `processOptions`.
// This actually makes the request and processes the response, so `createRequest`
// is a bit of a misnomer.
// okay, we haven't timed out and we have a response
clearTimeout(timeout);
var createRequest = function(request) {
var timeout
;
response = new Response(response, request, function(response) {
var emit = function(event) {
if (request.emitter.listeners(response.status).length>0) {
request.emitter.emit(response.status,response);
} else {
if (request.emitter.listeners(event).length>0) {
request.emitter.emit(event,response);
} else if (!response.isRedirect) {
request.emitter.emit("response",response);
}
request.log.debug("Creating request ..");
request.log.debug(request);
// Choose which Node.js standard library to use. **Warning:** Shred has not
// been tested much with `https`.
var http = request.scheme == "http" ? HTTP : HTTPS;
// Set up the real request using the selected library. The request won't be
// sent until we call `.end()`.
request._raw = http.request({
host: request.host,
port: request.port,
method: request.method,
path: request.path+request.query,
headers: request.getHeaders()
// Provide a response handler.
}, function(response) {
request.log.debug("Received response ..");
// We haven't timed out and we have a response, so make sure we clear the
// timeout so it doesn't fire while we're processing the response.
clearTimeout(timeout);
// Construct a Shred `Response` object from the response. This will stream
// the response, thus the need for the callback. We can access the response
// entity safely once we're in the callback.
response = new Response(response, request, function(response) {
// Set up some event magic. The precedence is given first to
// status-specific handlers, then to responses for a given event, and then
// finally to the more general `response` handler. In the last case, we
// need to first make sure we're not dealing with a a redirect.
var emit = function(event) {
if (request.emitter.listeners(response.status).length>0) {
request.emitter.emit(response.status,response);
} else {
if (request.emitter.listeners(event).length>0) {
request.emitter.emit(event,response);
} else if (!response.isRedirect) {
request.emitter.emit("response",response);
}
};
if (response.isRedirect) {
// just repeat the request with the new url
request.log.debug("Redirecting to "
+ response.getHeader("Location"));
request.url = response.getHeader("Location");
emit("redirect");
Private.createRequest(request);
} else if (response.isError) {
emit("error");
} else { // no error, no redirect
emit("success");
}
});
};
// Next, check for a redirect. We simply repeat the request with the URL
// given in the `Location` header. We fire a `redirect` event.
if (response.isRedirect) {
request.log.debug("Redirecting to "
+ response.getHeader("Location"));
request.url = response.getHeader("Location");
emit("redirect");
createRequest(request);
// Okay, it's not a redirect. Is it an error of some kind?
} else if (response.isError) {
emit("error");
} else {
// It looks like we're good shape. Trigger the `success` event.
emit("success");
}
});
});
request._raw.on("error", function(error) {
request.log.error("Request failed: " + error.message);
});
// We're still setting up the request. Next, we're going to handle error cases
// where we have no response. We don't emit an error event because that event
// takes a response. We don't response handlers to have to check for a null
// value. However, we [should introduce a different event
// type](https://github.com/spire-io/shred/issues/3) for this type of error.
request._raw.on("error", function(error) {
request.log.error("Request failed: " + error.message);
});
if (request.content) {
request.log.debug("Streaming body: '" +
request.content.body.slice(0,59) + "' ... ");
request._raw.write(request.content.body);
}
// We're almost there. Next, we need to write the request entity to the
// underlying request object.
if (request.content) {
request.log.debug("Streaming body: '" +
request.content.body.slice(0,59) + "' ... ");
request._raw.write(request.content.body);
}
if (request.timeout) {
timeout = setTimeout(function() {
request.log.debug("Timeout fired, aborting request ...");
request._raw.abort();
request.emit("timeout", request);
},request.timeout);
}
// Finally, we need to set up the timeout. We do this last so that we don't
// start the clock ticking until the last possible moment.
if (request.timeout) {
timeout = setTimeout(function() {
request.log.debug("Timeout fired, aborting request ...");
request._raw.abort();
request.emit("timeout", request);
},request.timeout);
}
// this will start the request
request.log.debug("Sending request ...");
request._raw.end();
}
// The `.end()` method will cause the request to fire. Technically, it might
// have already sent the headers and body.
request.log.debug("Sending request ...");
request._raw.end();
};
HeaderMixins.Getters.mixWith(Request);
HeaderMixins.Setters.mixWith(Request);
module.exports = Request;

@@ -0,14 +1,24 @@

// The `Response object` encapsulates a Node.js HTTP response.
var _ = require("underscore")
, Content = require("./content")
, HeaderMixins = require("./mixins/headers")
;
// Construct a `Response` object. You should never have to do this directly. The
// `Request` object handles this, getting the raw response object and passing it
// in here, along with the request. The callback allows us to stream the response
// and then use the callback to let the request know when it's ready.
var Response = function(raw, request, callback) {
var response = this;
this._raw = raw;
HeaderMixins.Setters.Methods.setHeaders.call(this,raw.headers);
// The `._setHeaders` method is "private"; you can't otherwise set headers on
// the response.
this._setHeaders.call(this,raw.headers);
this.request = request;
this.client = request.client;
this.log = this.request.log;
// Stream the response content entity and fire the callback when we're done.
var body = "";

@@ -25,2 +35,7 @@ raw.on("data", function(data) { body += data; });

// The `Response` object can be pretty overwhelming to view using the built-in
// Node.js inspect method. We want to make it a bit more manageable. This
// probably goes [too far in the other
// direction](https://github.com/spire-io/shred/issues/2).
Response.prototype = {

@@ -37,3 +52,6 @@ inspect: function() {

// `Response` object properties, all of which are read-only:
Object.defineProperties(Response.prototype, {
// - **status**. The HTTP status code for the response.
status: {

@@ -43,9 +61,18 @@ get: function() { return this._raw.statusCode; },

},
// - **content**. The HTTP content entity, if any. Provided as a [content
// object](./content.html), which will attempt to convert the entity based upon
// the `content-type` header. The converted value is available as
// `content.data`. The original raw content entity is available as
// `content.body`.
body: {
get: function() { return this._body; },
enumerable: true
get: function() { return this._body; }
},
content: {
get: function() { return this.body; }
get: function() { return this.body; },
enumerable: true
},
// - **isRedirect**. Is the response a redirect? These are responses with 3xx
// status and a `Location` header.
isRedirect: {

@@ -59,2 +86,5 @@ get: function() {

},
// - **isError**. Is the response an error? These are responses with status of
// 400 or greater.
isError: {

@@ -68,3 +98,5 @@ get: function() {

HeaderMixins.Getters.mixWith(Response);
// Add in the [getters for accessing the normalized headers](./headers.js).
HeaderMixins.getters(Response);
HeaderMixins.privateSetters(Response);
module.exports = Response;
{ "name": "shred"
, "version": "0.5.5"
, "version": "0.6.0"
, "description": "A dead-simple HTTP client"

@@ -4,0 +4,0 @@ , "keywords": [ "http", "client" ]

@@ -17,4 +17,3 @@ var vows = require('vows')

;
H.Getters.mixWith(K);
H.Setters.mixWith(K);
H.gettersAndSetters(K);

@@ -21,0 +20,0 @@ return K;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc