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

@adonisjs/http-server

Package Overview
Dependencies
Maintainers
2
Versions
137
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@adonisjs/http-server - npm Package Compare versions

Comparing version 2.1.2 to 3.0.0

build/exceptions.json

2

build/adonis-typings/request.d.ts

@@ -513,3 +513,3 @@ /**

allowMethodSpoofing: boolean;
getIp?: ((request: RequestContract) => string);
getIp?: (request: RequestContract) => string;
trustProxy: (address: string, distance: number) => boolean;

@@ -516,0 +516,0 @@ };

@@ -34,6 +34,2 @@ /**

/**
* Content types after processing response body
*/
export type ResponseContentType = 'text/html' | 'text/plain' | 'application/octet-stream' | 'application/json' | 'unknown' | 'null';
/**
* Types of readable stream allowed for HTTP response

@@ -43,9 +39,2 @@ */

/**
* Lazy body packet
*/
export type LazyBody = {
writer: any;
args: any[];
};
/**
* Main response interface

@@ -65,3 +54,3 @@ */

*/
lazyBody: LazyBody | null;
lazyBody: any[];
/**

@@ -193,18 +182,2 @@ * Returns a boolean telling if response is finished or not.

/**
* Builds the response body and returns it's appropriate type
* to be set as the content-type header.
*
* Ideally, you should use [[send]] vs using this method. This method will
* not set any headers and must be used when you want more control over the
* response sending process.
*
* Make sure to appropriately handle the case of `unknown` type, which is returned
* when unable to parse the body type.
*/
buildResponseBody(body: any): {
body: any;
type: ResponseContentType;
originalType?: string;
};
/**
* Send the body as response and optionally generate etag. The default value

@@ -258,3 +231,3 @@ * is read from `config/app.js` file, using `http.etag` property.

*/
stream(stream: ResponseStream, errorCallback?: ((error: NodeJS.ErrnoException) => any)): void;
stream(stream: ResponseStream, errorCallback?: (error: NodeJS.ErrnoException) => any): void;
/**

@@ -285,3 +258,3 @@ * Download file by streaming it from the file path. This method will setup

*/
download(filePath: string, generateEtag?: boolean, errorCallback?: ((error: NodeJS.ErrnoException) => any)): void;
download(filePath: string, generateEtag?: boolean, errorCallback?: (error: NodeJS.ErrnoException) => any): void;
/**

@@ -293,3 +266,3 @@ * Download the file by forcing the user to save the file vs displaying it

*/
attachment(filePath: string, name?: string, disposition?: string, generateEtag?: boolean, errorCallback?: ((error: NodeJS.ErrnoException) => any)): void;
attachment(filePath: string, name?: string, disposition?: string, generateEtag?: boolean, errorCallback?: (error: NodeJS.ErrnoException) => any): void;
/**

@@ -357,44 +330,44 @@ * Set the location header.

finish(): void;
continue(body: any, generateEtag?: boolean): void;
switchingProtocols(body: any, generateEtag?: boolean): void;
continue(): void;
switchingProtocols(): void;
ok(body: any, generateEtag?: boolean): void;
created(body: any, generateEtag?: boolean): void;
created(): void;
accepted(body: any, generateEtag?: boolean): void;
nonAuthoritativeInformation(body: any, generateEtag?: boolean): void;
noContent(body: any, generateEtag?: boolean): void;
resetContent(body: any, generateEtag?: boolean): void;
noContent(): void;
resetContent(): void;
partialContent(body: any, generateEtag?: boolean): void;
multipleChoices(body: any, generateEtag?: boolean): void;
movedPermanently(body: any, generateEtag?: boolean): void;
movedTemporarily(body: any, generateEtag?: boolean): void;
seeOther(body: any, generateEtag?: boolean): void;
notModified(body: any, generateEtag?: boolean): void;
useProxy(body: any, generateEtag?: boolean): void;
temporaryRedirect(body: any, generateEtag?: boolean): void;
badRequest(body: any, generateEtag?: boolean): void;
unauthorized(body: any, generateEtag?: boolean): void;
paymentRequired(body: any, generateEtag?: boolean): void;
forbidden(body: any, generateEtag?: boolean): void;
notFound(body: any, generateEtag?: boolean): void;
methodNotAllowed(body: any, generateEtag?: boolean): void;
notAcceptable(body: any, generateEtag?: boolean): void;
proxyAuthenticationRequired(body: any, generateEtag?: boolean): void;
requestTimeout(body: any, generateEtag?: boolean): void;
conflict(body: any, generateEtag?: boolean): void;
gone(body: any, generateEtag?: boolean): void;
lengthRequired(body: any, generateEtag?: boolean): void;
preconditionFailed(body: any, generateEtag?: boolean): void;
requestEntityTooLarge(body: any, generateEtag?: boolean): void;
requestUriTooLong(body: any, generateEtag?: boolean): void;
unsupportedMediaType(body: any, generateEtag?: boolean): void;
requestedRangeNotSatisfiable(body: any, generateEtag?: boolean): void;
expectationFailed(body: any, generateEtag?: boolean): void;
unprocessableEntity(body: any, generateEtag?: boolean): void;
tooManyRequests(body: any, generateEtag?: boolean): void;
internalServerError(body: any, generateEtag?: boolean): void;
notImplemented(body: any, generateEtag?: boolean): void;
badGateway(body: any, generateEtag?: boolean): void;
serviceUnavailable(body: any, generateEtag?: boolean): void;
gatewayTimeout(body: any, generateEtag?: boolean): void;
httpVersionNotSupported(body: any, generateEtag?: boolean): void;
multipleChoices(body?: any, generateEtag?: boolean): void;
movedPermanently(body?: any, generateEtag?: boolean): void;
movedTemporarily(body?: any, generateEtag?: boolean): void;
seeOther(body?: any, generateEtag?: boolean): void;
notModified(body?: any, generateEtag?: boolean): void;
useProxy(body?: any, generateEtag?: boolean): void;
temporaryRedirect(body?: any, generateEtag?: boolean): void;
badRequest(body?: any, generateEtag?: boolean): void;
unauthorized(body?: any, generateEtag?: boolean): void;
paymentRequired(body?: any, generateEtag?: boolean): void;
forbidden(body?: any, generateEtag?: boolean): void;
notFound(body?: any, generateEtag?: boolean): void;
methodNotAllowed(body?: any, generateEtag?: boolean): void;
notAcceptable(body?: any, generateEtag?: boolean): void;
proxyAuthenticationRequired(body?: any, generateEtag?: boolean): void;
requestTimeout(body?: any, generateEtag?: boolean): void;
conflict(body?: any, generateEtag?: boolean): void;
gone(body?: any, generateEtag?: boolean): void;
lengthRequired(body?: any, generateEtag?: boolean): void;
preconditionFailed(body?: any, generateEtag?: boolean): void;
requestEntityTooLarge(body?: any, generateEtag?: boolean): void;
requestUriTooLong(body?: any, generateEtag?: boolean): void;
unsupportedMediaType(body?: any, generateEtag?: boolean): void;
requestedRangeNotSatisfiable(body?: any, generateEtag?: boolean): void;
expectationFailed(body?: any, generateEtag?: boolean): void;
unprocessableEntity(body?: any, generateEtag?: boolean): void;
tooManyRequests(body?: any, generateEtag?: boolean): void;
internalServerError(body?: any, generateEtag?: boolean): void;
notImplemented(body?: any, generateEtag?: boolean): void;
badGateway(body?: any, generateEtag?: boolean): void;
serviceUnavailable(body?: any, generateEtag?: boolean): void;
gatewayTimeout(body?: any, generateEtag?: boolean): void;
httpVersionNotSupported(body?: any, generateEtag?: boolean): void;
}

@@ -401,0 +374,0 @@ /**

@@ -196,2 +196,3 @@ /**

}
export type ResourceRouteNames = 'create' | 'index' | 'store' | 'show' | 'edit' | 'update' | 'destroy';
/**

@@ -208,7 +209,7 @@ * Shape of route resource class

*/
only(names: string[]): this;
only(names: ResourceRouteNames[]): this;
/**
* Register all routes, except the one's defined
*/
except(names: string[]): this;
except(names: ResourceRouteNames[]): this;
/**

@@ -223,3 +224,5 @@ * Register api only routes. The `create` and `edit` routes, which

middleware(middleware: {
[name: string]: MiddlewareHandler | MiddlewareHandler[];
[P in ResourceRouteNames]?: MiddlewareHandler | MiddlewareHandler[];
} & {
'*'?: MiddlewareHandler | MiddlewareHandler[];
}): this;

@@ -226,0 +229,0 @@ /**

@@ -11,20 +11,20 @@ /**

export default class HttpServerProvider {
protected $container: IocContract;
constructor($container: IocContract);
protected container: IocContract;
constructor(container: IocContract);
/**
* Register request and response bindings to the container
*/
protected $registerRequestResponse(): void;
protected registerRequestResponse(): void;
/**
* Registering middleware store to the container
*/
protected $registerMiddlewareStore(): void;
protected registerMiddlewareStore(): void;
/**
* Registering the HTTP context
*/
protected $registerHTTPContext(): void;
protected registerHTTPContext(): void;
/**
* Register the HTTP server
*/
protected $registerHttpServer(): void;
protected registerHttpServer(): void;
/**

@@ -34,3 +34,3 @@ * Register the router. The router points to the instance of router used

*/
protected $registerRouter(): void;
protected registerRouter(): void;
/**

@@ -37,0 +37,0 @@ * Registering all bindings

@@ -11,10 +11,5 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const Server_1 = require("../src/Server");
const Request_1 = require("../src/Request");
const Response_1 = require("../src/Response");
const HttpContext_1 = require("../src/HttpContext");
const MiddlewareStore_1 = require("../src/MiddlewareStore");
class HttpServerProvider {
constructor($container) {
this.$container = $container;
constructor(container) {
this.container = container;
}

@@ -24,5 +19,9 @@ /**

*/
$registerRequestResponse() {
this.$container.bind('Adonis/Core/Request', () => Request_1.Request);
this.$container.bind('Adonis/Core/Response', () => Response_1.Response);
registerRequestResponse() {
this.container.singleton('Adonis/Core/Request', () => {
return require('../src/Request').Request;
});
this.container.singleton('Adonis/Core/Response', () => {
return require('../src/Response').Response;
});
}

@@ -32,4 +31,6 @@ /**

*/
$registerMiddlewareStore() {
this.$container.bind('Adonis/Core/MiddlewareStore', () => MiddlewareStore_1.MiddlewareStore);
registerMiddlewareStore() {
this.container.bind('Adonis/Core/MiddlewareStore', () => {
return require('../src/MiddlewareStore').MiddlewareStore;
});
}

@@ -39,4 +40,6 @@ /**

*/
$registerHTTPContext() {
this.$container.bind('Adonis/Core/HttpContext', () => HttpContext_1.HttpContext);
registerHTTPContext() {
this.container.bind('Adonis/Core/HttpContext', () => {
return require('../src/HttpContext').HttpContext;
});
}

@@ -46,10 +49,10 @@ /**

*/
$registerHttpServer() {
this.$container.singleton('Adonis/Core/Server', () => {
const Logger = this.$container.use('Adonis/Core/Logger');
const Profiler = this.$container.use('Adonis/Core/Profiler');
const Config = this.$container.use('Adonis/Core/Config');
const Encryption = this.$container.use('Adonis/Core/Encryption');
const config = Object.assign({ secret: Config.get('app.appKey') }, Config.get('app.http', {}));
return new Server_1.Server(this.$container, Logger, Profiler, Encryption, config);
registerHttpServer() {
this.container.singleton('Adonis/Core/Server', () => {
const { Server } = require('../src/Server');
const Logger = this.container.use('Adonis/Core/Logger');
const Profiler = this.container.use('Adonis/Core/Profiler');
const Config = this.container.use('Adonis/Core/Config');
const Encryption = this.container.use('Adonis/Core/Encryption');
return new Server(this.container, Logger, Profiler, Encryption, Config.get('app.http', {}));
});

@@ -61,5 +64,5 @@ }

*/
$registerRouter() {
this.$container.singleton('Adonis/Core/Route', () => {
return this.$container.use('Adonis/Core/Server').router;
registerRouter() {
this.container.singleton('Adonis/Core/Route', () => {
return this.container.use('Adonis/Core/Server').router;
});

@@ -71,9 +74,9 @@ }

register() {
this.$registerRequestResponse();
this.$registerMiddlewareStore();
this.$registerHttpServer();
this.$registerHTTPContext();
this.$registerRouter();
this.registerRequestResponse();
this.registerMiddlewareStore();
this.registerHttpServer();
this.registerHTTPContext();
this.registerRouter();
}
}
exports.default = HttpServerProvider;

@@ -57,3 +57,3 @@ "use strict";

let expires = options === null || options === void 0 ? void 0 : options.expires;
if (typeof (expires) === 'function') {
if (typeof expires === 'function') {
expires = expires();

@@ -65,3 +65,3 @@ }

let maxAge = options === null || options === void 0 ? void 0 : options.maxAge;
if (typeof (maxAge) === 'string') {
if (typeof maxAge === 'string') {
maxAge = ms_1.default(maxAge) / 1000;

@@ -68,0 +68,0 @@ }

@@ -10,2 +10,4 @@ /**

/// <reference path="../adonis-typings/index.d.ts" />
/// <reference types="node" />
import { Stats } from 'fs';
import { Route } from './Router/Route';

@@ -15,4 +17,4 @@ import { RouteGroup } from './Router/Group';

import { RouteResource } from './Router/Resource';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import { RouteJSON, MakeUrlOptions, MakeSignedUrlOptions } from '@ioc:Adonis/Core/Route';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
/**

@@ -55,1 +57,5 @@ * Makes input string consistent by having only the starting

};
/**
* Wraps `fs.stat` to promise interface.
*/
export declare function statFn(filePath: string): Promise<Stats>;

@@ -14,9 +14,10 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeMakeSignedUrlOptions = exports.normalizeMakeUrlOptions = exports.trustProxy = exports.useReturnValue = exports.processPattern = exports.toRoutesJSON = exports.dropSlash = void 0;
exports.statFn = exports.normalizeMakeSignedUrlOptions = exports.normalizeMakeUrlOptions = exports.trustProxy = exports.useReturnValue = exports.processPattern = exports.toRoutesJSON = exports.dropSlash = void 0;
/// <reference path="../adonis-typings/index.ts" />
const quick_lru_1 = __importDefault(require("quick-lru"));
const utils_1 = require("@poppinss/utils");
const fs_1 = require("fs");
const Group_1 = require("./Router/Group");
const BriskRoute_1 = require("./Router/BriskRoute");
const Resource_1 = require("./Router/Resource");
const RouterException_1 = require("./Exceptions/RouterException");
const proxyCache = new quick_lru_1.default({ maxSize: 100 });

@@ -74,3 +75,4 @@ /**

*/
url = tokens.map((token) => {
url = tokens
.map((token) => {
if (!token.startsWith(':')) {

@@ -86,6 +88,7 @@ return token;

if (!param && !isOptional) {
throw new utils_1.Exception(`\`${paramName}\` param is required to make URL for \`${pattern}\` route`, 500, 'E_MISSING_ROUTE_PARAM_VALUE');
throw RouterException_1.RouterException.cannotMakeRoute(paramName, pattern);
}
return param;
}).join('/');
})
.join('/');
}

@@ -152,1 +155,16 @@ return url;

exports.normalizeMakeSignedUrlOptions = normalizeMakeSignedUrlOptions;
/**
* Wraps `fs.stat` to promise interface.
*/
function statFn(filePath) {
return new Promise((resolve, reject) => {
fs_1.stat(filePath, (error, stats) => {
if (error) {
reject(error);
return;
}
resolve(stats);
});
});
}
exports.statFn = statFn;

@@ -55,7 +55,9 @@ "use strict";

resolveMiddleware(middleware) {
return typeof (middleware) === 'function' ? {
type: 'function',
value: middleware,
args: [],
} : Object.assign(this.resolver.resolve(`${middleware}.handle`), { args: [] });
return typeof middleware === 'function'
? {
type: 'function',
value: middleware,
args: [],
}
: Object.assign(this.resolver.resolve(`${middleware}.handle`), { args: [] });
}

@@ -62,0 +64,0 @@ /**

@@ -12,4 +12,7 @@ /**

import { IncomingMessage } from 'http';
import { RouterContract, MakeUrlOptions } from '@ioc:Adonis/Core/Route';
import { RedirectContract, ResponseContract } from '@ioc:Adonis/Core/Response';
import { RouterContract, MakeUrlOptions } from '@ioc:Adonis/Core/Route';
/**
* Exposes the API to construct redirect routes
*/
export declare class Redirect implements RedirectContract {

@@ -19,4 +22,13 @@ private request;

private router;
/**
* A boolean to forward the existing query string
*/
private forwardQueryString;
/**
* The status code for the redirect
*/
private statusCode;
/**
* A custom query string to forward
*/
private queryString;

@@ -23,0 +35,0 @@ constructor(request: IncomingMessage, response: ResponseContract, router: RouterContract);

@@ -19,2 +19,6 @@ "use strict";

const encodeurl_1 = __importDefault(require("encodeurl"));
const RouterException_1 = require("../Exceptions/RouterException");
/**
* Exposes the API to construct redirect routes
*/
class Redirect {

@@ -25,4 +29,13 @@ constructor(request, response, router) {

this.router = router;
/**
* A boolean to forward the existing query string
*/
this.forwardQueryString = false;
/**
* The status code for the redirect
*/
this.statusCode = 302;
/**
* A custom query string to forward
*/
this.queryString = {};

@@ -53,4 +66,8 @@ }

back() {
const url = (this.request.headers['referer'] || this.request.headers['referrer'] || '/');
return this.toPath(url);
let url = this.request.headers['referer'] || this.request.headers['referrer'] || '/';
url = Array.isArray(url) ? url[0] : url;
/**
* Remove query string from the referrer
*/
return this.toPath(url.split('?')[0]);
}

@@ -61,7 +78,6 @@ /**

toRoute(routeIdentifier, urlOptions, domain) {
const route = this.router.lookup(routeIdentifier, domain);
if (!route) {
throw new Error(`Unable to lookup route for "${routeIdentifier}" identifier`);
const url = this.router.makeUrl(routeIdentifier, urlOptions, domain);
if (!url) {
throw RouterException_1.RouterException.cannotLookupRoute(routeIdentifier);
}
const url = this.router.makeUrl(routeIdentifier, urlOptions, domain);
return this.toPath(url);

@@ -68,0 +84,0 @@ }

@@ -316,3 +316,3 @@ "use strict";

const ipFn = this.config.getIp;
if (typeof (ipFn) === 'function') {
if (typeof ipFn === 'function') {
return ipFn(this);

@@ -319,0 +319,0 @@ }

@@ -13,3 +13,3 @@ /**

import { ServerResponse, IncomingMessage } from 'http';
import { LazyBody, CookieOptions, CastableHeader, ResponseConfig, ResponseStream, ResponseContract, RedirectContract, ResponseContentType } from '@ioc:Adonis/Core/Response';
import { CookieOptions, CastableHeader, ResponseConfig, ResponseStream, ResponseContract, RedirectContract } from '@ioc:Adonis/Core/Response';
import { RouterContract } from '@ioc:Adonis/Core/Route';

@@ -21,21 +21,2 @@ import { EncryptionContract } from '@ioc:Adonis/Core/Encryption';

* streamlining the process of writing response body and automatically setting up appropriate headers.
*
* The response class has support for `explicitEnd` mode, which is set to true by default.
*
* When implicit end is set to true, the response class will not write content to the HTTP response
* directly and instead waits for an explicit call to the `finish` method. This is done to
* allow `return` statements from controllers.
*
* This is how `explicitEnd` mode works in nutshell.
*
* **When set to true**
* 1. Calls to `send`, `json` and `jsonp` will be buffered until `finish` is called.
* 2. `response.hasLazyBody` returns `true` after calling `send`, `json` or `jsonp`.
* 3. If `response.hasLazyBody` return `false`, then server will use the `return value` of the controller
* and set it as body before calling `finish`.
*
* **When set to false**
* 1. Calls to `send`, `json` and `jsonp` will write the response writeaway.
* 2. The `return value` of the controller will be discarded.
* 3. The call to `finish` method is a noop.
*/

@@ -52,11 +33,14 @@ export declare class Response extends Macroable implements ResponseContract {

private explicitStatus;
private writerMethod;
private cookieSerializer;
/**
* Returns a boolean telling if lazy body is already set or not
*/
hasLazyBody: boolean;
/**
* Lazy body is used to set the response body. However, do not
* write it on the socket immediately unless `response.finish`
* is called.
*
* Only works with `explicitEnd=true`, which is set to `false` by default
*/
lazyBody: LazyBody | null;
lazyBody: any[];
/**

@@ -69,6 +53,2 @@ * The ctx will be set by the context itself. It creates a circular

/**
* Returns a boolean telling if lazy body is already set or not
*/
get hasLazyBody(): boolean;
/**
* Returns a boolean telling if response is finished or not.

@@ -96,2 +76,17 @@ * Any more attempts to update headers or body will result

/**
* Ends the response by flushing headers and writing body
*/
private endResponse;
/**
* Returns type for the content body. Only following types are allowed
*
* - Dates
* - Arrays
* - Booleans
* - Objects
* - Strings
* - Buffer
*/
private getDataType;
/**
* Writes the body with appropriate response headers. Etag header is set

@@ -102,16 +97,12 @@ * when `generateEtag` is set to `true`.

*/
private writeBody;
protected writeBody(content: any, generateEtag: boolean, jsonpCallbackName?: string): void;
/**
* Stream the body to the response and handles cleaning up the stream
*/
private streamBody;
protected streamBody(body: ResponseStream, errorCallback?: (error: NodeJS.ErrnoException) => [string, number?]): Promise<unknown>;
/**
* Downloads a file by streaming it to the response
*/
private streamFileForDownload;
protected streamFileForDownload(filePath: string, generateEtag: boolean, errorCallback?: (error: NodeJS.ErrnoException) => [string, number?]): Promise<unknown>;
/**
* Ends the response by flushing headers and writing body
*/
private endResponse;
/**
* Writes headers to the response.

@@ -217,18 +208,2 @@ */

/**
* Builds the response body and returns it's appropriate type
* to be set as the content-type header.
*
* Ideally, you should use [[send]] vs using this method. This method will
* not set any headers and must be used when you want more control over the
* response sending process.
*
* Make sure to appropriately handle the case of `unknown` type, which is returned
* when unable to parse the body type.
*/
buildResponseBody(body: any): {
body: any;
type: ResponseContentType;
originalType?: string;
};
/**
* Send the body as response and optionally generate etag. The default value

@@ -282,3 +257,3 @@ * is read from `config/app.js` file, using `http.etag` property.

*/
stream(body: ResponseStream, errorCallback?: ((error: NodeJS.ErrnoException) => [string, number?])): void;
stream(body: ResponseStream, errorCallback?: (error: NodeJS.ErrnoException) => [string, number?]): void;
/**

@@ -309,3 +284,3 @@ * Download file by streaming it from the file path. This method will setup

*/
download(filePath: string, generateEtag?: boolean, errorCallback?: ((error: NodeJS.ErrnoException) => [string, number?])): void;
download(filePath: string, generateEtag?: boolean, errorCallback?: (error: NodeJS.ErrnoException) => [string, number?]): void;
/**

@@ -317,3 +292,3 @@ * Download the file by forcing the user to save the file vs displaying it

*/
attachment(filePath: string, name?: string, disposition?: string, generateEtag?: boolean, errorCallback?: ((error: NodeJS.ErrnoException) => [string, number?])): void;
attachment(filePath: string, name?: string, disposition?: string, generateEtag?: boolean, errorCallback?: (error: NodeJS.ErrnoException) => [string, number?]): void;
/**

@@ -381,44 +356,44 @@ * Set the location header.

finish(): void;
continue(body: any, generateEtag?: boolean): void;
switchingProtocols(body: any, generateEtag?: boolean): void;
continue(): void;
switchingProtocols(): void;
ok(body: any, generateEtag?: boolean): void;
created(body: any, generateEtag?: boolean): void;
created(): void;
accepted(body: any, generateEtag?: boolean): void;
nonAuthoritativeInformation(body: any, generateEtag?: boolean): void;
noContent(body: any, generateEtag?: boolean): void;
resetContent(body: any, generateEtag?: boolean): void;
noContent(): void;
resetContent(): void;
partialContent(body: any, generateEtag?: boolean): void;
multipleChoices(body: any, generateEtag?: boolean): void;
movedPermanently(body: any, generateEtag?: boolean): void;
movedTemporarily(body: any, generateEtag?: boolean): void;
seeOther(body: any, generateEtag?: boolean): void;
notModified(body: any, generateEtag?: boolean): void;
useProxy(body: any, generateEtag?: boolean): void;
temporaryRedirect(body: any, generateEtag?: boolean): void;
badRequest(body: any, generateEtag?: boolean): void;
unauthorized(body: any, generateEtag?: boolean): void;
paymentRequired(body: any, generateEtag?: boolean): void;
forbidden(body: any, generateEtag?: boolean): void;
notFound(body: any, generateEtag?: boolean): void;
methodNotAllowed(body: any, generateEtag?: boolean): void;
notAcceptable(body: any, generateEtag?: boolean): void;
proxyAuthenticationRequired(body: any, generateEtag?: boolean): void;
requestTimeout(body: any, generateEtag?: boolean): void;
conflict(body: any, generateEtag?: boolean): void;
gone(body: any, generateEtag?: boolean): void;
lengthRequired(body: any, generateEtag?: boolean): void;
preconditionFailed(body: any, generateEtag?: boolean): void;
requestEntityTooLarge(body: any, generateEtag?: boolean): void;
requestUriTooLong(body: any, generateEtag?: boolean): void;
unsupportedMediaType(body: any, generateEtag?: boolean): void;
requestedRangeNotSatisfiable(body: any, generateEtag?: boolean): void;
expectationFailed(body: any, generateEtag?: boolean): void;
unprocessableEntity(body: any, generateEtag?: boolean): void;
tooManyRequests(body: any, generateEtag?: boolean): void;
internalServerError(body: any, generateEtag?: boolean): void;
notImplemented(body: any, generateEtag?: boolean): void;
badGateway(body: any, generateEtag?: boolean): void;
serviceUnavailable(body: any, generateEtag?: boolean): void;
gatewayTimeout(body: any, generateEtag?: boolean): void;
httpVersionNotSupported(body: any, generateEtag?: boolean): void;
multipleChoices(body?: any, generateEtag?: boolean): void;
movedPermanently(body?: any, generateEtag?: boolean): void;
movedTemporarily(body?: any, generateEtag?: boolean): void;
seeOther(body?: any, generateEtag?: boolean): void;
notModified(body?: any, generateEtag?: boolean): void;
useProxy(body?: any, generateEtag?: boolean): void;
temporaryRedirect(body?: any, generateEtag?: boolean): void;
badRequest(body?: any, generateEtag?: boolean): void;
unauthorized(body?: any, generateEtag?: boolean): void;
paymentRequired(body?: any, generateEtag?: boolean): void;
forbidden(body?: any, generateEtag?: boolean): void;
notFound(body?: any, generateEtag?: boolean): void;
methodNotAllowed(body?: any, generateEtag?: boolean): void;
notAcceptable(body?: any, generateEtag?: boolean): void;
proxyAuthenticationRequired(body?: any, generateEtag?: boolean): void;
requestTimeout(body?: any, generateEtag?: boolean): void;
conflict(body?: any, generateEtag?: boolean): void;
gone(body?: any, generateEtag?: boolean): void;
lengthRequired(body?: any, generateEtag?: boolean): void;
preconditionFailed(body?: any, generateEtag?: boolean): void;
requestEntityTooLarge(body?: any, generateEtag?: boolean): void;
requestUriTooLong(body?: any, generateEtag?: boolean): void;
unsupportedMediaType(body?: any, generateEtag?: boolean): void;
requestedRangeNotSatisfiable(body?: any, generateEtag?: boolean): void;
expectationFailed(body?: any, generateEtag?: boolean): void;
unprocessableEntity(body?: any, generateEtag?: boolean): void;
tooManyRequests(body?: any, generateEtag?: boolean): void;
internalServerError(body?: any, generateEtag?: boolean): void;
notImplemented(body?: any, generateEtag?: boolean): void;
badGateway(body?: any, generateEtag?: boolean): void;
serviceUnavailable(body?: any, generateEtag?: boolean): void;
gatewayTimeout(body?: any, generateEtag?: boolean): void;
httpVersionNotSupported(body?: any, generateEtag?: boolean): void;
}

@@ -24,68 +24,13 @@ "use strict";

const macroable_1 = require("macroable");
const utils_1 = require("@poppinss/utils");
const fs_1 = require("fs");
const content_disposition_1 = __importDefault(require("content-disposition"));
const utils_1 = require("@poppinss/utils");
const helpers_1 = require("../helpers");
const Redirect_1 = require("../Redirect");
const Serializer_1 = require("../Cookie/Serializer");
const HttpException_1 = require("../Exceptions/HttpException");
const exceptions_json_1 = require("../../exceptions.json");
/**
* Wraps `fs.stat` to promise interface.
*/
function statFn(filePath) {
return new Promise((resolve, reject) => {
fs_1.stat(filePath, (error, stats) => {
if (error) {
reject(error);
return;
}
resolve(stats);
});
});
}
/**
* Custom exception to abort requests as one liners
*/
class HttpException extends utils_1.Exception {
/**
* This method returns an instance of the exception class
*/
static invoke(body, status) {
if (body !== null && typeof (body) === 'object') {
const error = new this(body.message || `Request aborted with status code${status}`, status);
error.body = body;
return error;
}
const error = new this(body || `Request aborted with status code${status}`, status);
error.body = error.message;
return error;
}
/**
* Handle itself by making the response. This only works when using the
* base exception handler shipped by AdonisJs
*/
handle(error, ctx) {
ctx.response.status(error.status).send(error.body);
}
}
/**
* The response is a wrapper over [ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse)
* streamlining the process of writing response body and automatically setting up appropriate headers.
*
* The response class has support for `explicitEnd` mode, which is set to true by default.
*
* When implicit end is set to true, the response class will not write content to the HTTP response
* directly and instead waits for an explicit call to the `finish` method. This is done to
* allow `return` statements from controllers.
*
* This is how `explicitEnd` mode works in nutshell.
*
* **When set to true**
* 1. Calls to `send`, `json` and `jsonp` will be buffered until `finish` is called.
* 2. `response.hasLazyBody` returns `true` after calling `send`, `json` or `jsonp`.
* 3. If `response.hasLazyBody` return `false`, then server will use the `return value` of the controller
* and set it as body before calling `finish`.
*
* **When set to false**
* 1. Calls to `send`, `json` and `jsonp` will write the response writeaway.
* 2. The `return value` of the controller will be discarded.
* 3. The call to `finish` method is a noop.
*/

@@ -102,19 +47,16 @@ class Response extends macroable_1.Macroable {

this.explicitStatus = false;
this.writerMethod = 'endResponse';
this.cookieSerializer = new Serializer_1.CookieSerializer(this.encryption);
/**
* Returns a boolean telling if lazy body is already set or not
*/
this.hasLazyBody = false;
/**
* Lazy body is used to set the response body. However, do not
* write it on the socket immediately unless `response.finish`
* is called.
*
* Only works with `explicitEnd=true`, which is set to `false` by default
*/
this.lazyBody = null;
this.lazyBody = [];
}
/**
* Returns a boolean telling if lazy body is already set or not
*/
get hasLazyBody() {
return !!(this.lazyBody && this.lazyBody.writer);
}
/**
* Returns a boolean telling if response is finished or not.

@@ -141,3 +83,3 @@ * Any more attempts to update headers or body will result

get isPending() {
return (!this.headersSent && !this.finished);
return !this.headersSent && !this.finished;
}

@@ -151,2 +93,39 @@ /**

/**
* Ends the response by flushing headers and writing body
*/
endResponse(body, statusCode) {
this.flushHeaders(statusCode);
// avoid ArgumentsAdaptorTrampoline from V8 (inspired by fastify)
const res = this.response;
res.end(body, null, null);
}
/**
* Returns type for the content body. Only following types are allowed
*
* - Dates
* - Arrays
* - Booleans
* - Objects
* - Strings
* - Buffer
*/
getDataType(content) {
const dataType = typeof content;
if (Buffer.isBuffer(content)) {
return 'buffer';
}
if (dataType === 'number' || dataType === 'boolean' || dataType === 'string') {
return dataType;
}
if (content instanceof Date) {
return 'date';
}
if (dataType === 'object' && content instanceof RegExp === false) {
return 'object';
}
const error = new utils_1.Exception(utils_1.interpolate(exceptions_json_1.E_CANNOT_SERIALIZE_RESPONSE_BODY.message, { dataType }), exceptions_json_1.E_CANNOT_SERIALIZE_RESPONSE_BODY.status, exceptions_json_1.E_CANNOT_SERIALIZE_RESPONSE_BODY.code);
error.help = exceptions_json_1.E_CANNOT_SERIALIZE_RESPONSE_BODY.help.join('\n');
throw error;
}
/**
* Writes the body with appropriate response headers. Etag header is set

@@ -158,51 +137,47 @@ * when `generateEtag` is set to `true`.

writeBody(content, generateEtag, jsonpCallbackName) {
let { type, body, originalType } = this.buildResponseBody(content);
/*
* Send 204 and remove content headers when body
* is null
*/
if (body === null) {
if (content === null || content === undefined || content === '') {
this.safeStatus(204);
this.removeHeader('Content-Type');
this.removeHeader('Content-Length');
this.removeHeader('Transfer-Encoding');
this.endResponse();
return;
}
/*
* Unknown types are not serializable
const isEmptyBody = this.response.statusCode === 204;
const isNotModified = this.response.statusCode === 304;
/**
* Do not process body when status code is less than 200 or is 204 or 304. As per
* https://tools.ietf.org/html/rfc7230#section-3.3.2
*/
if (type === 'unknown') {
throw new Error(`Cannot send ${originalType} as HTTP response`);
}
/*
* In case of 204 and 304, remove unwanted headers
*/
if ([204, 304].indexOf(this.response.statusCode) > -1) {
if (isEmptyBody ||
isNotModified ||
(this.response.statusCode && this.response.statusCode < 200)) {
this.removeHeader('Content-Type');
this.removeHeader('Content-Length');
this.removeHeader('Transfer-Encoding');
this.endResponse(body);
isNotModified ? this.endResponse(content) : this.endResponse();
return;
}
/*
* Decide correct content-type header based upon the existence of
* JSONP callback.
/**
* Javascript data type for the content. We only handle a subset
* of data types. Check [[this.getDataType]] method for more
* info
*/
if (jsonpCallbackName) {
this.header('X-Content-Type-Options', 'nosniff');
this.safeHeader('Content-Type', 'text/javascript; charset=utf-8');
const dataType = this.getDataType(content);
/**
* ----------------------------------------
* SERIALIZE CONTENT TO A STRING
* ----------------------------------------
*
* Transforming date, number, boolean and object to a string
*/
if (dataType === 'number' || dataType === 'boolean') {
content = String(content);
}
else {
this.safeHeader('Content-Type', `${type}; charset=utf-8`);
else if (dataType === 'date') {
content = content.toISOString();
}
/*
* Generate etag if instructed. This is send using the request
* body, which adds little delay to the response but ensures
* unique etag based on body
*/
if (generateEtag) {
this.setEtag(body);
else if (dataType === 'object') {
content = JSON.stringify(content);
}
/*
* ----------------------------------------
* MORE MODIFICATIONS FOR JSONP BODY
* ----------------------------------------
*
* If JSONP callback exists, then update the body to be a

@@ -216,3 +191,3 @@ * valid JSONP response

*/
body = body.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
content = content.replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
// the /**/ is a specific security mitigation for "Rosetta Flash JSONP abuse"

@@ -222,9 +197,61 @@ // https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-4671

// http://drops.wooyun.org/tips/2554
body = `/**/ typeof ${jsonpCallbackName} === 'function' && ${jsonpCallbackName}(${body});`;
content = `/**/ typeof ${jsonpCallbackName} === 'function' && ${jsonpCallbackName}(${content});`;
}
/*
* Compute content length
* ----------------------------------------
* FINALY GENERATE AN ETAG
* ----------------------------------------
*
* Generate etag if instructed.
*/
this.header('Content-Length', Buffer.byteLength(body));
this.endResponse(body);
if (generateEtag) {
this.setEtag(content);
}
/*
* ----------------------------------------
* SET CONTENT-LENGTH HEADER
* ----------------------------------------
*/
this.header('Content-Length', Buffer.byteLength(content));
/**
* ----------------------------------------
* SET CONTENT-TYPE HEADER
* ----------------------------------------
*
* - If it is a JSONP response, then we always set the content type
* to "text/javascript"
*
* - String are checked for HTML and "text/plain" or "text/html" is set
* accordingly.
*
* - "text/plain" is set for "numbers" and "booleans" and "dates"
*
* - "application/octet-stream" is set for buffers
*
* - "application/json" is set for objects and arrays
*/
if (jsonpCallbackName) {
this.header('X-Content-Type-Options', 'nosniff');
this.safeHeader('Content-Type', 'text/javascript; charset=utf-8');
}
else {
switch (dataType) {
case 'string':
const type = /^\s*</.test(content) ? 'text/html' : 'text/plain';
this.safeHeader('Content-Type', `${type}; charset=utf-8`);
break;
case 'number':
case 'boolean':
case 'date':
this.safeHeader('Content-Type', 'text/plain; charset=utf-8');
break;
case 'buffer':
this.safeHeader('Content-Type', 'application/octet-stream; charset=utf-8');
break;
case 'object':
this.safeHeader('Content-Type', 'application/json; charset=utf-8');
break;
}
}
this.endResponse(content);
}

@@ -249,3 +276,3 @@ /**

this.type('text');
if (typeof (errorCallback) === 'function') {
if (typeof errorCallback === 'function') {
this.endResponse(...errorCallback(error));

@@ -281,5 +308,5 @@ }

try {
const stats = await statFn(filePath);
const stats = await helpers_1.statFn(filePath);
if (!stats || !stats.isFile()) {
throw new Error('response.download only accepts path to a file');
throw new utils_1.Exception('response.download only accepts path to a file');
}

@@ -331,3 +358,3 @@ /*

this.type('text');
if (typeof (errorCallback) === 'function') {
if (typeof errorCallback === 'function') {
this.endResponse(...errorCallback(error));

@@ -341,11 +368,2 @@ }

/**
* Ends the response by flushing headers and writing body
*/
endResponse(body, statusCode) {
this.flushHeaders(statusCode);
// avoid ArgumentsAdaptorTrampoline from V8 (inspired by fastify)
const res = this.response;
res.end(body, null, null);
}
/**
* Writes headers to the response.

@@ -355,3 +373,2 @@ */

this.response.writeHead(statusCode || this.response.statusCode, this.headers);
this.headers = {};
return this;

@@ -412,3 +429,5 @@ }

existingHeader = this.castHeaderValue(existingHeader);
casted = Array.isArray(existingHeader) ? existingHeader.concat(casted) : [existingHeader].concat(casted);
casted = Array.isArray(existingHeader)
? existingHeader.concat(casted)
: [existingHeader].concat(casted);
this.headers[key] = casted;

@@ -430,3 +449,6 @@ return this;

removeHeader(key) {
delete this.headers[key.toLowerCase()];
key = key.toLowerCase();
if (this.headers[key]) {
delete this.headers[key.toLowerCase()];
}
return this;

@@ -523,71 +545,2 @@ }

/**
* Builds the response body and returns it's appropriate type
* to be set as the content-type header.
*
* Ideally, you should use [[send]] vs using this method. This method will
* not set any headers and must be used when you want more control over the
* response sending process.
*
* Make sure to appropriately handle the case of `unknown` type, which is returned
* when unable to parse the body type.
*/
buildResponseBody(body) {
if (body === null || body === undefined) {
return {
body: null,
type: 'null',
};
}
/*
* Set type to `text/html` or `text/plain` when body is a
* plain string
*/
if (typeof (body) === 'string') {
return body.length === 0
? {
body: null,
type: 'null',
}
: {
body,
type: /^\s*</.test(body) ? 'text/html' : 'text/plain',
};
}
/*
* Buffer sets the body as `application/octet-stream`
*/
if (Buffer.isBuffer(body)) {
return {
body,
type: 'application/octet-stream',
};
}
/*
* Cast boolean and numbers to string.
*/
if (typeof (body) === 'number' || typeof (body) === 'boolean') {
return {
body: String(body),
type: 'text/plain',
};
}
/*
* Cast objects as string by `JSON.stringify`.
*/
if (typeof (body) === 'object') {
return {
body: JSON.stringify(body),
type: 'application/json',
};
}
/*
* Unknown body type.
*/
return {
body,
originalType: typeof (body),
type: 'unknown',
};
}
/**
* Send the body as response and optionally generate etag. The default value

@@ -600,6 +553,5 @@ * is read from `config/app.js` file, using `http.etag` property.

send(body, generateEtag = this.config.etag) {
this.lazyBody = {
writer: this.writeBody,
args: [body, generateEtag],
};
this.writerMethod = 'writeBody';
this.hasLazyBody = true;
this.lazyBody = [body, generateEtag];
}

@@ -625,6 +577,5 @@ /**

jsonp(body, callbackName = this.config.jsonpCallbackName, generateEtag = this.config.etag) {
this.lazyBody = {
writer: this.writeBody,
args: [body, generateEtag, callbackName],
};
this.writerMethod = 'writeBody';
this.hasLazyBody = true;
this.lazyBody = [body, generateEtag, callbackName];
}

@@ -656,9 +607,8 @@ /**

stream(body, errorCallback) {
if (typeof (body.pipe) !== 'function' || !body.readable || typeof (body.read) !== 'function') {
throw new Error('response.stream accepts a readable stream only');
if (typeof body.pipe !== 'function' || !body.readable || typeof body.read !== 'function') {
throw new utils_1.Exception('response.stream accepts a readable stream only');
}
this.lazyBody = {
writer: this.streamBody,
args: [body, errorCallback],
};
this.writerMethod = 'streamBody';
this.hasLazyBody = true;
this.lazyBody = [body, errorCallback];
}

@@ -691,6 +641,5 @@ /**

download(filePath, generateEtag = this.config.etag, errorCallback) {
this.lazyBody = {
writer: this.streamFileForDownload,
args: [filePath, generateEtag, errorCallback],
};
this.writerMethod = 'streamFileForDownload';
this.hasLazyBody = true;
this.lazyBody = [filePath, generateEtag, errorCallback];
}

@@ -738,3 +687,3 @@ /**

abort(body, status) {
throw HttpException.invoke(body, status || 400);
throw HttpException_1.HttpException.invoke(body, status || 400);
}

@@ -819,17 +768,14 @@ /**

finish() {
if (this.lazyBody && this.isPending) {
this.lazyBody.writer.bind(this)(...this.lazyBody.args);
this.lazyBody = null;
if (!this.isPending) {
return;
}
else if (this.isPending) {
this.endResponse();
}
this[this.writerMethod](...this.lazyBody);
}
continue(body, generateEtag) {
continue() {
this.status(100);
return this.send(body, generateEtag);
return this.send(null, false);
}
switchingProtocols(body, generateEtag) {
switchingProtocols() {
this.status(101);
return this.send(body, generateEtag);
return this.send(null, false);
}

@@ -840,5 +786,5 @@ ok(body, generateEtag) {

}
created(body, generateEtag) {
created() {
this.status(201);
return this.send(body, generateEtag);
return this.send(null, false);
}

@@ -853,9 +799,9 @@ accepted(body, generateEtag) {

}
noContent(body, generateEtag) {
noContent() {
this.status(204);
return this.send(body, generateEtag);
return this.send(null, false);
}
resetContent(body, generateEtag) {
resetContent() {
this.status(205);
return this.send(body, generateEtag);
return this.send(null, false);
}

@@ -862,0 +808,0 @@ partialContent(body, generateEtag) {

@@ -14,8 +14,5 @@ "use strict";

const macroable_1 = require("macroable");
const utils_1 = require("@poppinss/utils");
const BriskRoute_1 = require("./BriskRoute");
const Resource_1 = require("./Resource");
function missingRouteName() {
return new utils_1.Exception('All routes inside a group must have names before calling Route.group.as', 500, 'E_MISSING_ROUTE_NAME');
}
const RouterException_1 = require("../Exceptions/RouterException");
/**

@@ -51,3 +48,3 @@ * Group class exposes the API to take action on a group of routes.

if (method === 'as' && !route.route.name) {
throw missingRouteName();
throw RouterException_1.RouterException.cannotDefineGroupName();
}

@@ -63,3 +60,3 @@ route.route[method](...params);

if (method === 'as' && !route.name) {
throw missingRouteName();
throw RouterException_1.RouterException.cannotDefineGroupName();
}

@@ -66,0 +63,0 @@ route[method](...params);

@@ -14,3 +14,2 @@ "use strict";

const qs_1 = require("qs");
const utils_1 = require("@poppinss/utils");
const Route_1 = require("./Route");

@@ -21,2 +20,3 @@ const Store_1 = require("./Store");

const Resource_1 = require("./Resource");
const RouterException_1 = require("../Exceptions/RouterException");
const helpers_1 = require("../helpers");

@@ -218,3 +218,3 @@ /**

where(param, matcher) {
this.matchers[param] = typeof (matcher) === 'string' ? new RegExp(matcher) : matcher;
this.matchers[param] = typeof matcher === 'string' ? new RegExp(matcher) : matcher;
return this;

@@ -240,3 +240,3 @@ }

if (route.name && names.indexOf(route.name) > -1) {
throw new utils_1.Exception(`Duplicate route name \`${route.name}\``, 500, 'E_DUPLICATE_ROUTE_NAME');
throw RouterException_1.RouterException.duplicateRouteName(route.name);
}

@@ -310,5 +310,6 @@ /*

lookup(routeIdentifier, forDomain) {
return this.lookupStore.find(({ name, pattern, handler, domain }) => {
return [name, pattern, handler].indexOf(routeIdentifier) > -1 && (!forDomain || forDomain === domain);
}) || null;
return (this.lookupStore.find(({ name, pattern, handler, domain }) => {
return ([name, pattern, handler].indexOf(routeIdentifier) > -1 &&
(!forDomain || forDomain === domain));
}) || null);
}

@@ -361,5 +362,3 @@ /**

*/
const signature = this.encryption
.verifier
.sign(this.makeUrl(route.pattern, {
const signature = this.encryption.verifier.sign(this.makeUrl(route.pattern, {
qs: options.qs,

@@ -366,0 +365,0 @@ params: options.params,

@@ -12,3 +12,3 @@ /**

import { MiddlewareHandler } from '@ioc:Adonis/Core/Middleware';
import { RouteMatchers, RouteResourceContract } from '@ioc:Adonis/Core/Route';
import { RouteMatchers, RouteResourceContract, ResourceRouteNames } from '@ioc:Adonis/Core/Route';
import { Route } from './Route';

@@ -56,7 +56,7 @@ /**

*/
only(names: string[]): this;
only(names: ResourceRouteNames[]): this;
/**
* Register all routes, except the one's defined
*/
except(names: string[]): this;
except(names: ResourceRouteNames[]): this;
/**

@@ -71,3 +71,5 @@ * Register api only routes. The `create` and `edit` routes, which

middleware(middleware: {
[name: string]: MiddlewareHandler | MiddlewareHandler[];
[P in ResourceRouteNames]?: MiddlewareHandler | MiddlewareHandler[];
} & {
'*'?: MiddlewareHandler | MiddlewareHandler[];
}): this;

@@ -74,0 +76,0 @@ /**

@@ -43,3 +43,4 @@ "use strict";

.split('.')
.map((token) => utils_1.lodash.snakeCase(token)).join('.');
.map((token) => utils_1.lodash.snakeCase(token))
.join('.');
this.buildRoutes();

@@ -101,3 +102,3 @@ }

apiOnly() {
return this.except(['.create', '.edit']);
return this.except(['create', 'edit']);
}

@@ -104,0 +105,0 @@ /**

@@ -79,3 +79,7 @@ "use strict";

const pattern = helpers_1.dropSlash(this.pattern);
const prefix = this.prefixes.slice().reverse().map((one) => helpers_1.dropSlash(one)).join('');
const prefix = this.prefixes
.slice()
.reverse()
.map((one) => helpers_1.dropSlash(one))
.join('');
return prefix ? `${prefix}${pattern === '/' ? '' : pattern}` : pattern;

@@ -100,3 +104,3 @@ }

}
this.matchers[param] = typeof (matcher) === 'string' ? new RegExp(matcher) : matcher;
this.matchers[param] = typeof matcher === 'string' ? new RegExp(matcher) : matcher;
return this;

@@ -131,3 +135,5 @@ }

middleware = Array.isArray(middleware) ? middleware : [middleware];
this.routeMiddleware = prepend ? middleware.concat(this.routeMiddleware) : this.routeMiddleware.concat(middleware);
this.routeMiddleware = prepend
? middleware.concat(this.routeMiddleware)
: this.routeMiddleware.concat(middleware);
return this;

@@ -134,0 +140,0 @@ }

@@ -18,2 +18,3 @@ "use strict";

const utils_1 = require("@poppinss/utils");
const RouterException_1 = require("../Exceptions/RouterException");
/**

@@ -120,9 +121,3 @@ * Store class is used to store a list of routes, along side with their tokens

const routeJSON = {};
utils_1.lodash.merge(routeJSON, utils_1.lodash.pick(route, [
'pattern',
'handler',
'meta',
'middleware',
'name',
]));
utils_1.lodash.merge(routeJSON, utils_1.lodash.pick(route, ['pattern', 'handler', 'meta', 'middleware', 'name']));
/*

@@ -146,3 +141,3 @@ * An explicit domain is defined

if (collectedParams.has(token.val)) {
throw new utils_1.Exception(`Duplicate route param "${token.val}" in route ${route.pattern}`, 500, 'E_DUPLICATE_ROUTE');
throw RouterException_1.RouterException.duplicateRouteParam(token.val, route.pattern);
}

@@ -163,3 +158,3 @@ else {

if (methodRoutes.routes[route.pattern]) {
throw new utils_1.Exception(`Duplicate route \`${method}:${route.pattern}\``, 500, 'E_DUPLICATE_ROUTE');
throw RouterException_1.RouterException.duplicateRoute(method, route.pattern);
}

@@ -215,4 +210,3 @@ methodRoutes.tokens.push(tokens);

params: matchit_1.default.exec(url, matchedRoute),
subdomains: (domain === null || domain === void 0 ? void 0 : domain.value) ? matchit_1.default.exec(domain.value, domain.storeMatch)
: {},
subdomains: (domain === null || domain === void 0 ? void 0 : domain.value) ? matchit_1.default.exec(domain.value, domain.storeMatch) : {},
};

@@ -219,0 +213,0 @@ }

@@ -27,3 +27,3 @@ "use strict";

registerHandler(handler) {
if (typeof (handler) === 'string') {
if (typeof handler === 'string') {
this.resolvedErrorHandler = {

@@ -85,3 +85,3 @@ type: 'class',

this.resolvedErrorHandler.type === 'class' &&
typeof (this.resolvedErrorHandler.value['report']) === 'function') {
typeof this.resolvedErrorHandler.value['report'] === 'function') {
try {

@@ -88,0 +88,0 @@ await this.resolvedErrorHandler.value['report'](error, ctx);

@@ -63,3 +63,3 @@ "use strict";

*/
if (httpConfig.cookie.maxAge && typeof (httpConfig.cookie.maxAge) === 'string') {
if (httpConfig.cookie.maxAge && typeof httpConfig.cookie.maxAge === 'string') {
httpConfig.cookie.maxAge = ms_1.default(httpConfig.cookie.maxAge) / 1000;

@@ -76,6 +76,7 @@ }

*/
const shortcircuit = await this.hooks.executeBefore(ctx);
if (!shortcircuit) {
await this.requestHandler.handle(ctx);
}
return this.hooks.executeBefore(ctx).then((shortcircuit) => {
if (!shortcircuit) {
return this.requestHandler.handle(ctx);
}
});
}

@@ -145,3 +146,9 @@ /**

/*
* Excute hooks when there are one or more hooks
* Excute hooks when there are one or more hooks. The `ctx.response.finish`
* is intentionally inside both the `try` and `catch` blocks as a defensive
* measure.
*
* When we call `response.finish`, it will serialize the response body and may
* encouter errors while doing so and hence will be catched by the catch
* block.
*/

@@ -148,0 +155,0 @@ try {

@@ -11,4 +11,4 @@ /**

import { RouteNode } from '@ioc:Adonis/Core/Route';
import { IocContract } from '@adonisjs/fold';
import { MiddlewareStoreContract } from '@ioc:Adonis/Core/Middleware';
import { IocContract } from '@adonisjs/fold';
/**

@@ -27,7 +27,11 @@ * Precompiler is used to pre compiler the route handler and middleware. We

*/
private finalRouteHandler;
private runRouteHandler;
/**
* Method to execute middleware using the middleware store
*/
private executeMiddleware;
/**
* This function is used by reference to execute the route middleware + route handler
*/
private routeMiddlewareHandler;
private runRouteMiddleware;
/**

@@ -34,0 +38,0 @@ * The resolver used to resolve the controllers from IoC container

@@ -20,2 +20,3 @@ "use strict";

const helpers_1 = require("../../helpers");
const exceptions_json_1 = require("../../../exceptions.json");
/**

@@ -35,5 +36,4 @@ * Precompiler is used to pre compiler the route handler and middleware. We

*/
this.finalRouteHandler = async function finalRouteHandler(ctx) {
let data = {};
let requestProfiler = ctx.profiler;
this.runRouteHandler = async (ctx) => {
const routeHandler = ctx.route.meta.resolvedHandler;
/*

@@ -43,37 +43,30 @@ * Passing a child to the route handler, so that all internal

*/
ctx.profiler = ctx.profiler.create('http:route:handler', data);
const routeHandler = ctx.route.meta.resolvedHandler;
let returnValue;
try {
if (routeHandler.type === 'function') {
returnValue = await routeHandler.handler(ctx);
}
else {
data.controller = routeHandler.namespace;
data.method = routeHandler.method;
returnValue = await this.resolver.call(routeHandler, ctx.route.meta.namespace, [ctx]);
}
if (helpers_1.useReturnValue(returnValue, ctx)) {
ctx.response.send(returnValue);
}
ctx.profiler.end();
ctx.profiler = requestProfiler;
if (routeHandler.type === 'function') {
returnValue = await routeHandler.handler(ctx);
}
catch (error) {
ctx.profiler.end();
ctx.profiler = requestProfiler;
throw error;
else {
returnValue = await this.resolver.call(routeHandler, ctx.route.meta.namespace, [ctx]);
}
}.bind(this);
if (helpers_1.useReturnValue(returnValue, ctx)) {
ctx.response.send(returnValue);
}
};
/**
* Method to execute middleware using the middleware store
*/
this.executeMiddleware = (middleware, params) => {
return this.middlewareStore.invokeMiddleware(middleware, params);
};
/**
* This function is used by reference to execute the route middleware + route handler
*/
this.routeMiddlewareHandler = async function routeMiddlewareHandler(ctx) {
await new co_compose_1.Middleware()
this.runRouteMiddleware = (ctx) => {
return new co_compose_1.Middleware()
.register(ctx.route.meta.resolvedMiddleware)
.runner()
.resolve(this.middlewareStore.invokeMiddleware.bind(this.middlewareStore))
.finalHandler(this.finalRouteHandler, [ctx])
.executor(this.executeMiddleware)
.finalHandler(this.runRouteHandler, [ctx])
.run([ctx]);
}.bind(this);
};
this.resolver = container.getResolver(undefined, 'httpControllers', 'App/Controllers/Http');

@@ -85,3 +78,3 @@ }

compileHandler(route) {
if (typeof (route.handler) === 'string') {
if (typeof route.handler === 'string') {
route.meta.resolvedHandler = this.resolver.resolve(route.handler, route.meta.namespace);

@@ -98,3 +91,3 @@ }

route.meta.resolvedMiddleware = route.middleware.map((item) => {
if (typeof (item) === 'function') {
if (typeof item === 'function') {
return { type: 'function', value: item, args: [] };

@@ -112,3 +105,5 @@ }

if (!resolvedMiddleware) {
throw new utils_1.Exception(`Cannot find named middleware ${name}`, 500, 'E_MISSING_NAMED_MIDDLEWARE');
const error = new utils_1.Exception(utils_1.interpolate(exceptions_json_1.E_MISSING_NAMED_MIDDLEWARE.message, { name }), exceptions_json_1.E_MISSING_NAMED_MIDDLEWARE.status, exceptions_json_1.E_MISSING_NAMED_MIDDLEWARE.code);
error.help = exceptions_json_1.E_MISSING_NAMED_MIDDLEWARE.help.join('\n');
throw error;
}

@@ -126,6 +121,6 @@ resolvedMiddleware.args = args;

if (route.meta.resolvedMiddleware && route.meta.resolvedMiddleware.length) {
route.meta.finalHandler = this.routeMiddlewareHandler;
route.meta.finalHandler = this.runRouteMiddleware;
}
else {
route.meta.finalHandler = this.finalRouteHandler;
route.meta.finalHandler = this.runRouteHandler;
}

@@ -132,0 +127,0 @@ }

@@ -10,5 +10,5 @@ /**

/// <reference path="../../../adonis-typings/index.d.ts" />
import { RouterContract } from '@ioc:Adonis/Core/Route';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import { MiddlewareStoreContract } from '@ioc:Adonis/Core/Middleware';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import { RouterContract } from '@ioc:Adonis/Core/Route';
/**

@@ -22,7 +22,8 @@ * Handles the request by invoking it's middleware chain, along with the

private globalMiddleware;
private handleRequest;
constructor(middlewareStore: MiddlewareStoreContract, router: RouterContract);
/**
* Executes the middleware chain, followed by the route handler.
* Function to invoke global middleware
*/
private invokeHandler;
private executeMiddleware;
/**

@@ -29,0 +30,0 @@ * Finds the route for the request

@@ -13,4 +13,6 @@ "use strict";

/// <reference path="../../../adonis-typings/index.ts" />
const co_compose_1 = require("co-compose");
const utils_1 = require("@poppinss/utils");
const co_compose_1 = require("co-compose");
const HttpException_1 = require("../../Exceptions/HttpException");
const exceptions_json_1 = require("../../../exceptions.json");
/**

@@ -24,15 +26,10 @@ * Handles the request by invoking it's middleware chain, along with the

this.router = router;
/**
* Function to invoke global middleware
*/
this.executeMiddleware = (middleware, params) => {
return this.middlewareStore.invokeMiddleware(middleware, params);
};
}
/**
* Executes the middleware chain, followed by the route handler.
*/
async invokeHandler(ctx) {
await this
.globalMiddleware
.runner()
.resolve(this.middlewareStore.invokeMiddleware.bind(this.middlewareStore))
.finalHandler(ctx.route.meta.finalHandler, [ctx])
.run([ctx]);
}
/**
* Finds the route for the request

@@ -54,3 +51,3 @@ */

if (!route) {
throw new utils_1.Exception(`Cannot ${method}:${url}`, 404, 'E_ROUTE_NOT_FOUND');
throw HttpException_1.HttpException.invoke(utils_1.interpolate(exceptions_json_1.E_ROUTE_NOT_FOUND.message, { method, url }), exceptions_json_1.E_ROUTE_NOT_FOUND.status, exceptions_json_1.E_ROUTE_NOT_FOUND.code);
}

@@ -71,3 +68,3 @@ /*

this.findRoute(ctx);
await this.invokeHandler(ctx);
return this.handleRequest(ctx);
}

@@ -79,10 +76,16 @@ /**

const middleware = this.middlewareStore.get();
if (middleware.length) {
this.globalMiddleware = new co_compose_1.Middleware().register(middleware);
if (!middleware.length) {
this.handleRequest = (ctx) => ctx.route.meta.finalHandler(ctx);
return;
}
else {
this.invokeHandler = async (ctx) => ctx.route.meta.finalHandler(ctx);
}
this.globalMiddleware = new co_compose_1.Middleware().register(middleware);
this.handleRequest = (ctx) => {
return this.globalMiddleware
.runner()
.executor(this.executeMiddleware)
.finalHandler(ctx.route.meta.finalHandler, [ctx])
.run([ctx]);
};
}
}
exports.RequestHandler = RequestHandler;
# The MIT License
Copyright 2019 Harminder virk, contributors
Copyright 2020 Harminder virk, contributors

@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

{
"name": "@adonisjs/http-server",
"version": "2.1.2",
"version": "3.0.0",
"description": "AdonisJS HTTP server with support packed with Routing and Cookies",
"main": "build/providers/HttpServerProvider.js",
"files": [
"build/adonis-typings",
"build/providers",
"build/src",
"build/providers",
"build/adonis-typings",
"build/exceptions.json",
"build/standalone.d.ts",

@@ -17,3 +18,2 @@ "build/standalone.js"

"test": "node japaFile.js",
"lint": "eslint . --ext=.ts",
"clean": "del build",

@@ -26,3 +26,7 @@ "compile": "npm run lint && npm run clean && tsc",

"release": "np",
"version": "npm run build:tmp"
"version": "npm run build",
"prepublishOnly": "npm run build",
"lint": "eslint . --ext=.ts",
"format": "prettier --write .",
"sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json adonisjs/http-server"
},

@@ -36,15 +40,17 @@ "keywords": [

"devDependencies": {
"@adonisjs/encryption": "^2.0.4",
"@adonisjs/application": "^2.0.0",
"@adonisjs/config": "^1.1.0",
"@adonisjs/encryption": "^2.0.6",
"@adonisjs/fold": "^6.3.5",
"@adonisjs/logger": "^2.0.6",
"@adonisjs/mrm-preset": "^2.3.0",
"@adonisjs/profiler": "^3.0.4",
"@poppinss/dev-utils": "^1.0.6",
"@adonisjs/logger": "^2.1.0",
"@adonisjs/mrm-preset": "^2.4.0",
"@adonisjs/profiler": "^4.0.1",
"@poppinss/dev-utils": "^1.0.8",
"@types/cookie": "^0.4.0",
"@types/ms": "^0.7.31",
"@types/node": "^14.0.13",
"@types/node": "^14.0.25",
"@types/pluralize": "0.0.29",
"@types/proxy-addr": "^2.0.0",
"@types/qs": "^6.9.3",
"@types/supertest": "^2.0.9",
"@types/supertest": "^2.0.10",
"autocannon": "^5.0.1",

@@ -55,5 +61,8 @@ "commitizen": "^4.1.2",

"doctoc": "^1.4.0",
"eslint": "^7.2.0",
"eslint-plugin-adonis": "^1.0.10",
"fastify": "^2.14.1",
"eslint": "^7.5.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-adonis": "^1.0.14",
"eslint-plugin-prettier": "^3.1.4",
"fastify": "^3.1.1",
"github-label-sync": "^2.0.0",
"http-status-codes": "^1.4.0",

@@ -63,8 +72,10 @@ "husky": "^4.2.5",

"mrm": "^2.3.3",
"np": "^6.2.4",
"np": "^6.3.2",
"npm-audit-html": "^1.4.1",
"pem": "^1.14.4",
"prettier": "^2.0.5",
"reflect-metadata": "^0.1.13",
"supertest": "^4.0.2",
"ts-node": "^8.10.2",
"typescript": "^3.9.5"
"typescript": "^3.9.7"
},

@@ -86,3 +97,3 @@ "peerDependencies": {

"hooks": {
"pre-commit": "doctoc README.md --title='## Table of contents' && git add README.md",
"pre-commit": "npm audit --production --json | ./node_modules/.bin/npm-audit-html && git add npm-audit.html",
"commit-msg": "node ./node_modules/@adonisjs/mrm-preset/validateCommit/conventional/validate.js"

@@ -101,5 +112,5 @@ }

"dependencies": {
"@poppinss/utils": "^2.2.7",
"@poppinss/utils": "^2.4.1",
"accepts": "^1.3.7",
"co-compose": "^5.1.5",
"co-compose": "^6.0.1",
"content-disposition": "^0.5.3",

@@ -113,3 +124,3 @@ "cookie": "^0.4.1",

"haye": "^2.0.2",
"macroable": "^4.0.4",
"macroable": "^5.0.1",
"matchit": "git+https://github.com/thetutlage/matchit.git",

@@ -137,3 +148,6 @@ "mime-types": "^2.1.27",

},
"homepage": "https://github.com/adonisjs/http-server#readme"
"homepage": "https://github.com/adonisjs/http-server#readme",
"adonisjs": {
"exceptions": "./build/exceptions.json"
}
}

@@ -1,93 +0,44 @@

<div align="center"><img src="https://res.cloudinary.com/adonisjs/image/upload/q_100/v1564392111/adonis-banner_o9lunk.png" width="600px"></div>
<div align="center">
<img src="https://res.cloudinary.com/adonisjs/image/upload/q_100/v1558612869/adonis-readme_zscycu.jpg" width="600px">
</div>
# AdonisJS Http Server
> Decently fast HTTP server used by AdonisJS
<br />
[![appveyor-image]][appveyor-url] [![circleci-image]][circleci-url] [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url]
<div align="center">
<h3>AdonisJS HTTP Server</h3>
<p>A fully featured HTTP server with first class support for <strong>Route groups</strong>, <strong>Sub-domain routing</strong>, <strong>Middleware</strong> and <strong>Cookies</strong>.</p>
</div>
This module is extracted from the AdonisJS framework to work as a standalone HTTP server. The performance of the server is on par with Fastify (not as fast as fastify though).
<br />
<div align="center">
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
## Table of contents
[![circleci-image]][circleci-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url] [![audit-report-image]][audit-report-url]
- [Benchmarks](#benchmarks)
- [Features](#features)
- [Usage](#usage)
</div>
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
<div align="center">
<h3>
<a href="https://preview.adonisjs.com">
Website
</a>
<span> | </span>
<a href="https://preview.adonisjs.com/guides/http/introduction">
Guides
</a>
<span> | </span>
<a href="CONTRIBUTING.md">
Contributing
</a>
<span> | </span>
<a href="benchmarks.md">
Benchmarks
</a>
</h3>
</div>
## Benchmarks
The benchmarking scheme is taken from the Fastify github repo.
<div align="center">
<sub>Built with ❤︎ by <a href="https://twitter.com/AmanVirk1">Harminder Virk</a>
</div>
**Machine**: Quad-Core Intel Core i7, 2.2GHz, 16GB RAM
**Method**: autocannon -c 100 -d 40 -p 10 localhost:3000 * 2, taking the second average
| Framework | Version | Router? | Requests/sec |
| :----------------- | :------------------------- | :----------: | ------------: |
| **Fastify** | **2.0.0** | **&#10003;** | **58,740** |
| **AdonisJS** | **1.8.1** | **&#10003;** | **54,832** |
You can run the same benchmarks by cloning the repo and then running the following command.
```sh
npm run benchmark
```
Since the program correctness and reliability is more important over micro optimizations. We pay penality on following fronts in comparison to Fastify.
- **The AdonisJS query string parser can parse arrays inside query string** `(/api?foo[]=bar&foo[]=fuzz&foo[]=buzz
)`, wherease fastify doesn't parse it by default for performance reasons. However, you can also define your own query string parser with fastify, but again, you will end up paying the same performance penality.
- **Subdomain based routing** is another front, where AdonisJS has to perform little bit extra work to find the correct route and it's handler.
## Features
- The most advanced router with support for **route resources**, **route groups**, **subdomains routing**.
- Support for **global** and **route specific** middleware.
- Reliable and stable query string parser.
- Global exception handler to catch all exceptions handled during an HTTP request.
- Sends data to AdonisJS inbuilt profiler
## Usage
You must be using the server inside a fully fledged AdonisJS application. Still, here's how you can start the standlone server.
```sh
npm i @adonisjs/http-server
```
```ts
import proxyaddr from 'proxy-addr'
import { createServer } from 'http'
import { Ioc } from '@adonisjs/fold'
import { Logger } from '@adonisjs/logger/build/standalone'
import { Profiler } from '@adonisjs/profiler/build/standalone'
import { Encryption } from '@adonisjs/encryption/build/standalone'
import { Server } from '@adonisjs/http-server'
const logger = new Logger({ enabled: true, level: 'trace', name: 'adonis' })
const profiler = new Profiler({ enabled: true })
const encryption = new Encryption({
secret: 'averylongrandom32charslongsecret',
})
const server = new Server(new Ioc(), logger, profiler, encryption, {
etag: false,
jsonpCallbackName: 'callback',
cookie: {},
subdomainOffset: 2,
generateRequestId: false,
trustProxy: proxyaddr.compile('loopback'),
allowMethodSpoofing: false,
})
server.router.get('/', async () => {
return { hello: 'world' }
})
server.optimize()
createServer(server.handle.bind(server)).listen(4000)
```
[appveyor-image]: https://img.shields.io/appveyor/ci/thetutlage/http-server/master.svg?style=for-the-badge&logo=appveyor

@@ -107,1 +58,4 @@ [appveyor-url]: https://ci.appveyor.com/project/thetutlage/http-server "appveyor"

[license-url]: LICENSE.md "license"
[audit-report-image]: https://img.shields.io/badge/-Audit%20Report-blueviolet?style=for-the-badge
[audit-report-url]: https://htmlpreview.github.io/?https://github.com/adonisjs/http-server/blob/develop/npm-audit.html "audit-report"
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