Skip to content

Commit

Permalink
fix: asJson for controller
Browse files Browse the repository at this point in the history
create CookieData class
set version 1.1.2
  • Loading branch information
sanchezzzhak committed Jun 26, 2024
1 parent 0b7fbb8 commit 28fc635
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 9 deletions.
9 changes: 7 additions & 2 deletions demo/controllers/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ const {AbstractController} = require('../../src/index');
class HomeController extends AbstractController {

async index() {
this.initRequest();
this.cookieData.set('server-test-cookie', '1', {
expires: new Date() + 36000
})
return this.renderRaw({
view: `<!DOCTYPE html>
<html>
Expand All @@ -21,10 +25,11 @@ class HomeController extends AbstractController {
}

async about() {
return 'page about';
this.initRequest();
let cookieValue = this.cookieData.get('server-test-cookie', '0');
return 'page about cookie value ' + cookieValue;
}


async test() {
return this.redirect('/about');
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-moleculer-web",
"version": "1.1.1",
"version": "1.1.2",
"description": "Fast web app service for moleculer.js + uWebSockets.js",
"main": "src/index.js",
"repository": {
Expand Down
13 changes: 7 additions & 6 deletions src/abstract-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const {getMime} = require('./utils/mime');
const HTTP_CODES = require('./utils/http-codes');
const Timer = require("./utils/timer");
const RequestData = require("./request-data");

const CookieData = require("./cookie-data");

/** @typedef {import("uWebSockets.js").HttpRequest} HttpRequest */
/** @typedef {import("uWebSockets.js").HttpResponse} HttpResponse */
Expand Down Expand Up @@ -40,11 +40,11 @@ const readBody = (res, cb, err) => {
res.onAborted(err);
};



class AbstractController {
/** @type {RequestData|null} */
requestData = null;
/** @type {CookieData|null} */
cookieData = null;
format = 'html';
statusCode = 200;
statusCodeText = '200 OK';
Expand All @@ -69,6 +69,7 @@ class AbstractController {

initRequest() {
this.requestData = new RequestData(this.req, this.res);
this.cookieData = new CookieData(this.req, this.res);
if (this.clientHints) {
this.setClientHintsHeaders();
}
Expand All @@ -90,10 +91,10 @@ class AbstractController {
/**
* final response as JSON
* @param {JSONObject} obj
* @param {number} statusCode
* @param {number} httpCode
*/
asJson(obj, statusCode = 200) {
return this.renderRaw({view: JSON.stringify(obj), statusCode, format: 'json'});
asJson(obj, httpCode = 200) {
return this.renderRaw({view: JSON.stringify(obj), httpCode, format: 'json'});
}

writeHeader(key, value) {
Expand Down
146 changes: 146 additions & 0 deletions src/cookie-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/** @typedef {import("uWebSockets.js").HttpRequest} HttpRequest */
/** @typedef {import("uWebSockets.js").HttpResponse} HttpResponse */

const {escape} = require('node:querystring');

const ucFirst = (string) => {
let str = string.toLowerCase();
return str[0].toUpperCase() + str.substring(1, str.length);
}

const converter = {
read: (value) => {
if (value[0] === '"') {
value = value.slice(1, -1)
}
return value.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent)
},
write: (value) => {
return encodeURIComponent(value).replace(
/%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g,
decodeURIComponent
)
},
name: (name) => {
return encodeURIComponent(name)
.replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent)
.replace(/[()]/g, escape)
}
}

const DAY = 864e5;

class CookieData {

reqs = {}; // request data from req
resp = {}; // response data to write header

/**
* init and parse cookie for request data
* @param {HttpRequest} req
* @param {HttpResponse} res
*/
constructor(req, res) {
let cookies = req.getHeader('cookie').split('; ')
let jar = {};
for (let i = 0; i < cookies.length; i++) {
let parts = cookies[i].split('=')
let value = parts.slice(1).join('=')
try {
let found = decodeURIComponent(parts[0])
if (!(found in jar)) jar[found] = {value: converter.read(value)}
if (name === found) {
break
}
} catch {}
}
this.reqs = jar;
}

/**
* get cookie
* @param {string} name
* @param {*} defaultValue
* @return {null}
*/
get(name, defaultValue = null) {
return this.reqs[name].value ?? defaultValue;
}

/**
* get by name record to write Set-Cookie header
* @param name
* @return {string}
*/
toHeader(name) {
let data = this.resp[name] ?? {};
let headers = [
`${name}=${data.value ?? ''}`,
data.path ? `; Path=${data.path}`: '',
data.domain ? `; Domain=${data.domain}`: '',
data.expires ? `; Expires=${data.expires}`: '',
data.secure ? '; Secure': '',
data.httpOnly ? '; HttpOnly': '',
data.partitioned ? '; Partitioned': '',
data.maxAge ? `; Max-Age=${Math.floor(data.maxAge)}`: '',
data.priority ? `; Priority=${ucFirst(data.priority)}`: '',
data.sameSite ? `; SameSite=${ucFirst(data.sameSite)}`: '',
];

return headers.join('');
}

/**
* set cookie
* @param {string} name
* @param {*} value
* @param {CookieOptions} options
*/
set(name, value, options= {}) {
if (options.path === void 0) {
options.path = '/'
}

if (typeof options.expires === 'number') {
options.expires = new Date(Date.now() + options.expires * DAY)
}

if (options.expires && options.expires.toUTCString) {
options.expires = options.expires.toUTCString()
}

let key = converter.name(name);

let data = Object.assign({}, {
...options,
value: converter.write(value),
})

this.resp[key] = data;
this.reqs[key] = data;
}

/**
* has request cookie key exist
* @param {string} name
* @return {boolean}
*/
has(name) {
return this.reqs[name] !== void 0;
}

/**
* remove cookie
* @param {string} name
* @param {CookieOptions} options
*/
remove(name, options = {}) {
this.set(name, '', {
...options,
expires: -1,
})
}

}

module.exports = CookieData;
24 changes: 24 additions & 0 deletions src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,29 @@ export class RequestData {
constructor(req: HttpRequest, res: HttpResponse)
}

export interface CookieOptions {
path?: string;
domain?: string;
sameSite?: "strict" | "lax" | "none";
priority?: "low" | "medium" | "high";
expires?: Date|number|string;
maxAge?: number;
secure?: boolean;
httpOnly?: boolean;
partitioned?: boolean;
}

export class CookieData {
reqs: {};
resp: {};
set(name: string, value: any, options?: CookieOptions): void;
get(name: string, defaultValue?: any): any;
has(name: string): boolean;
remove(name: string, options?: CookieOptions): void;
toHeader(name: string): string;
constructor(req: HttpRequest, res: HttpResponse)
}

export interface AbstractControllerOptions {
broker: ServiceBroker;
req: HttpRequest;
Expand All @@ -82,6 +105,7 @@ export interface AbstractControllerOptions {

export class AbstractController {
requestData: RequestData;
cookieData: CookieData;
format: string;
statusCode: number;
statusCodeText: string;
Expand Down
5 changes: 5 additions & 0 deletions src/uws-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ const UwsServer = {
res.writeHeader(key, controller.headers[key]);
}
}
if (controller !== null && controller.cookieData) {
for (let key in controller.cookieData.resp) {
res.writeHeader('set-cookie', controller.cookieData.toHeader(key));
}
}
controller !== null && controller.statusCodeText && res.writeStatus(controller.statusCodeText);
res.end(result);
});
Expand Down

0 comments on commit 28fc635

Please sign in to comment.