Skip to content

Commit

Permalink
blazed.js version 1.0.32
Browse files Browse the repository at this point in the history
Patch notes - 
1. Minor bug fixes.
2. Added a new promise based DNS resolving method. Checkout docs for more info.
3. Improved overall performance.
  • Loading branch information
BlazeInferno64 authored Oct 15, 2024
1 parent 9a6510f commit 22740ef
Show file tree
Hide file tree
Showing 11 changed files with 496 additions and 14 deletions.
87 changes: 87 additions & 0 deletions lib/node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,93 @@ blazed.get("https://api.github.com/users")

Stay up-to-date with our project for upcoming features and enhancements, including additional events that will be introduced in future releases.

# DNS resolving

In addition to making HTTP requests, `blazed.js` also provides an asynchronous way to resolve the DNS of various hostnames.

You can use the `blazed.resolve()` method to achieve this. It returns a promise that resolves with an IP object containing the resolved IP addresses and its format.

The object has the following structre:

```js

{
Format: string, // The IP address format (e.g., IPv4, IPv6). Optional. If not specified, **blazed.js** will resolve the promise with the first IP address found after performing a DNS lookup for the host
Addresses: Array, // The ip address of the host which has been resolved (Present in array)
}

```

### Accessing IP Object Properties

When logging the IP object, you can access its properties as follows (assuming the object is named `ipObj`):

* `ipObj.format`: The IP address format (e.g., 'IPv4' or 'IPv6').
* `ipObj.addresses`: The resolved IP addresses of the host.

Example demonstrating DNS resolving:

```js
// Resolving DNS using blazed.resolve() with specified ip format.

blazed.resolve({
/**
* The IP address format (e.g., 'IPv4' or 'IPv6'). Optional.
* If not specified, **blazed.js** will resolve the promise with the first IP address found after performing a DNS lookup for the host.
*/
format: "IPv4",

/**
* The hostname to resolve (e.g., 'www.google.com').
* Note: if you omit the protocol (http/https), you will get an error of invalid url.
*/
hostname: "https://www.google.com" // Let's take google.com here
})
.then(ipObj => {
// Logging the ipObj to the console.
return console.log(ipObj);
// ipObj contains:
// - Format (The format of the ip of the host)
// - Address (Array containing the list of ip addresses)
})
.catch(err => {
// Logging any errors to the console.
return console.error(err);
});
```


```js
// Resolving DNS using blazed.resolve() with specified ip format.
// Starting the request to resolve the hostname.

blazed.request({
/**
* The hostname to resolve (e.g., 'https://www.google.com').
* Note: if you omit the protocol (http/https), you will get an error of invalid url.
*/
hostname: "https://www.google.com" // Let's take google.com here
})
.then(ipObj => {
// Logging the ipObj to the console.
return console.log(ipObj);
// ipObj contains:
// - Format (The format of the ip of the host)
// - Address (Array containing the list of ip addresses)
})
.catch(err => {
// Logging any errors to the console.
return console.error(err);
});

```

### Underlying Technology

This feature is built on top of Node.js's built-in `dns` module, which provides an asynchronous network wrapper for performing DNS lookups.

For more information about the `dns` module, please refer to the [official Node.js documentation](https://nodejs.org/api/dns.html).

# Validating Header Names and Values

In addition to sending requests, you can also validate header names and values using the `blazed.validateHeaderName()` and `blazed.validateHeaderValue()` functions.
Expand Down
2 changes: 1 addition & 1 deletion lib/node/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

'use strict';
"use strict";
/**
* blazed.js is a blazing-fast, light weight, high-performance, promise-based HTTP client
*
Expand Down
26 changes: 21 additions & 5 deletions lib/node/lib/blazed.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
// Copyright (c) 2024 BlazeInferno64 --> https://github.com/blazeinferno64

'use strict';
"use strict";

const http = require('http');
const https = require('https');

const { EventEmitter } = require("events");
const emitter = new EventEmitter();

const urlParser = require("./utils/tools/url-parser");
const headerParser = require("./utils/tools/header-parser");
const httpErrors = require("./utils/tools/http-errors");
const urlParser = require("./utils/url-parser");
const headerParser = require("./utils/header-parser");
const httpErrors = require("./utils/errors");
const dnsResolver = require("./utils/dns");

const packageJson = require("../package.json");

Expand Down Expand Up @@ -328,6 +329,20 @@ const validateHeaderValue = async (name, value) => {
return await headerParser.parseThisHeaderValue(name, value);
}

/**
* Resolves a hostname's dns with a ip object contaning the ip addresses.
* @param {Object} hostObject - The object containing the host data
* @param {('IPv4'|'IPv6')} hostObject.format - Optional ip address format
* @param {string} hostObject.hostname - The hostname which you want to resolve
* @returns {Promise<Object>} Returns a promise which contains the resolved ip data
*/

const resolve = async (hostObject) => {
const url = hostObject.hostname;
const format = hostObject.format;
const parsedURL = new URL(url);
return await dnsResolver.lookupForIp(parsedURL.hostname, format, url);
}
/**
* @returns {Object} Returns a object which contains some info regarding blazed.js.
*/
Expand Down Expand Up @@ -472,7 +487,7 @@ module.exports = {
const method = object.method;
const headers = object.headers;
const data = object.body;
let redirectCount = object.redirectCount;
let redirectCount = object.limit;
if (!redirectCount) return redirectCount = 5; // If not specified make it 5 by default.

if (!http.METHODS.includes(method.toUpperCase())) {
Expand All @@ -491,6 +506,7 @@ module.exports = {
about,
validateHeaderName,
validateHeaderValue,
resolve,
/**
* Attaches a listener to the on event
* Fires up whenever a request is ready to send
Expand Down
75 changes: 75 additions & 0 deletions lib/node/lib/utils/dns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const dns = require("dns");
const net = require("net");

const { processError } = require("./errors");

/**
*
* @param {string} hostname - The hostname you want to resolve
* @param {string} type - The type/format of ip (eg. IPv4, IPv6)
* @returns {Promise<any>} - Returns a promise which resolves with the ip data
*/
const lookupForIp = async(hostname, type) => {
return await new Promise(async(resolve, reject) => {

//Define an ip object
const ipObj = {
Format: "",
Addresses: []
}

if (!type && typeof type === 'undefined') {
try {
return dns.lookup(hostname, async(err, address) => {
if (err) return reject({ error: await processError(err, hostname, 'Yes') });
ipObj.Addresses.push(address);
if (net.isIPv4(address)) {
ipObj.Format = "IPv4";
return resolve(ipObj);
}
else if (net.isIPv6(address)) {
ipObj.Format = "IPv6";
return resolve(ipObj);
}
else {
ipObj.Format = 'Unknown Format';
return resolve(ipObj);
}
})
} catch (error) {
return reject(await processError(error, hostname, 'Yes'));
}
}
else if (type !== '' && typeof type !== 'undefined') {
if (type === 'IPv4') {
try {
return dns.resolve4(hostname, async(err, addresses) => {
if (err) return reject({ error: await processError(err, hostname, 'Yes') });
ipObj.Format = 'IPv4';
ipObj.Addresses = addresses;
return resolve(ipObj);
})
} catch (error) {
return reject(await processError(error, hostname, 'Yes'));
}
} else if (type === "IPv6") {
try {
return dns.resolve6(hostname, async(err, addresses) => {
if (err) return reject({ error: await processError(err, hostname, 'Yes') });
ipObj.Format = 'IPv6';
ipObj.Addresses = addresses;
return resolve(ipObj);
})
} catch (error) {
return reject(await processError(error, hostname, 'Yes'));
}
} else {
return reject(`Unknown ip address format specified! Available formats - IPv4, IPv6`);
}
}
})
}

module.exports = {
lookupForIp
}
81 changes: 81 additions & 0 deletions lib/node/lib/utils/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use strict";
/**
* Util tool for processing http based common errors.
* @param {Object} error - The HTTP error you want to process.
* @returns {Promise<Object>} returns the processed error object as a promise.
*/
const processError = (error, url, dns) => {
return new Promise((resolve, reject) => {
if (error.code === 'ENOTFOUND') {
const err = new Error(`DNS Resolution Error`);
err.code = error.code;
err.name = "DNS_Resolution_Error";
err.hostname = url;
err.message = `Failed to resolve the DNS of '${url}'`;
return reject(err);
} else if (error.code === 'ETIMEOUT') {
const err = new Error(`Request Timeout`);
err.code = error.code;
err.name = "Request_Timeout_Error";
err.message = dns ? `The DNS request was timed out` : `The HTTP request to ${url} was timed out!`;
err.hostname = url;
return reject(err);
} else if (error.type === 'abort' || error.code === 'ABORT_ERR') {
const err = new Error(`Request Aborted`);
err.code = error.code;
err.name = "Request_Abort_Error";
err.message = `HTTP ${method} request to ${url} was aborted`;
return reject(err);
} else if (error.code === 'ECONNREFUSED') {
const err = new Error(`Connection Refused`);
err.code = error.code;
err.name = "Connection_Refused_Error"
err.message = dns? `Failed to lookup DNS of '${url}'` : `The server refused the connection for the HTTP ${method} request to ${url}`;
return reject(err);
} else if (error.code === 'ECONNRESET') {
const err = new Error(`Connection Reset`);
err.code = error.code;
err.name = "Connection_Reset_Error";
err.message = dns? `Connection reset while looking up for the DNS of '${url}'` : `The server reset the connection while sending the HTTP ${method} request to ${url}`;
return reject(err);
} else if (error.code === 'EPIPE') {
const err = new Error(`Broken Pipe`);
err.code = error.code;
err.name = "Broken_Pipe_Error";
err.url = url;
err.message = `The connection to ${url} was closed unexpectedly while sending the HTTP ${method} request`;
return reject(err);
} else if (error.code === 'EHOSTUNREACH') {
const err = new Error(`Host Unreachable`);
err.code = error.code;
err.name = "Host_Unreachable_Error";
err.message = `The host '${url}' is unreachable`;
return reject(err);
} else if (error.code === 'ENETUNREACH') {
const err = new Error(`Network Unreachable`);
err.code = error.code;
err.name = "Network_Unreachable_Error";
err.message = `The network is unreachable`;
return reject(err);
} else if (error.code === 'EHOSTDOWN') {
const err = new Error(`Host is down`);
err.code = error.code;
err.name = "Host_Down_Error";
err.message = `The host '${url}' is down`;
return reject(err);
} else if (error.code === 'ENETDOWN') {
const err = new Error(`Network is down`);
err.code = error.code;
err.name = "Network_Down_Error";
err.message = `The network is down`;
return reject(err);
}
else {
return reject(error);
}
})
}

module.exports = {
processError
}
Loading

0 comments on commit 22740ef

Please sign in to comment.