node-web-mvc
Version:
node spring mvc
110 lines (109 loc) • 4.51 kB
JavaScript
"use strict";
/**
* @moduel HttpRequestValidation
* @description http请求校验
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const RequestUtil_1 = __importDefault(require("../util/RequestUtil"));
const HttpHeaders_1 = __importDefault(require("./HttpHeaders"));
const HttpMethod_1 = __importDefault(require("./HttpMethod"));
const HttpStatus_1 = __importDefault(require("./HttpStatus"));
const etagRegex = new RegExp('\\*|\\s*((W\\/)?("[^"]*"))\\s*,?');
class HttpRequestValidation {
constructor(request, response) {
this.request = request;
this.response = response;
this.notModified = false;
}
normalizeTimestamp(lastModifiedTimestamp) {
// 时间戳精度设置在 1s误差
return parseInt((lastModifiedTimestamp / 1000).toString()) * 1000;
}
checkNotModified(etag, lastModifiedTimestamp) {
const method = this.request.method;
const isSafeMethod = method === HttpMethod_1.default.GET || method === HttpMethod_1.default.HEAD;
// 1. 校验 if-unmodified-since
if (this.validateIfUnmodifiedSince(lastModifiedTimestamp)) {
if (this.notModified) {
// 如果此时文件被修改了,这里需要设置返回412状态
this.response.setStatus(HttpStatus_1.default.PRECONDITION_FAILED);
}
return this.notModified;
}
// 2. 校验: if-none-match
if (!this.validateIfNoneMatch(etag)) {
// 3. 校验: if-modified-since
this.validateIfModifiedSince(lastModifiedTimestamp);
}
// 4. 进行304判定
if (this.notModified) {
const status = isSafeMethod ? HttpStatus_1.default.NOT_MODIFIED : HttpStatus_1.default.PRECONDITION_FAILED;
this.response.setStatus(status);
}
// 5. 写出 last-modifed 以及 etag
if (isSafeMethod) {
if (lastModifiedTimestamp > 0 && !this.response.getHeader(HttpHeaders_1.default.LAST_MODIFIED)) {
this.response.setDateHeader(HttpHeaders_1.default.LAST_MODIFIED, lastModifiedTimestamp);
}
if (etag && !this.response.getHeader(HttpHeaders_1.default.ETAG)) {
etag = RequestUtil_1.default.padEtagIfNecessary(etag);
this.response.setHeader(HttpHeaders_1.default.ETAG, etag);
}
}
if (this.notModified) {
this.response.end();
}
return this.notModified;
}
/**
* 校验当前请求头中带 if-unmodified-since
* @param lastModifiedTimestamp 资源最后修改时间
*/
validateIfUnmodifiedSince(lastModifiedTimestamp) {
const timestamp = this.normalizeTimestamp(lastModifiedTimestamp);
// 获取if-unmodified-since值
const ifUnmodifiedSince = RequestUtil_1.default.parseDataHeader(this.request, HttpHeaders_1.default.IF_UNMODIFIED_SINCE);
if (ifUnmodifiedSince === -1 || timestamp < 0) {
return false;
}
this.notModified = ifUnmodifiedSince < timestamp;
return true;
}
/**
* 校验if-none-match
* @returns 当前etag是否匹配成功
*/
validateIfNoneMatch(etag) {
const ifNoneMatch = this.request.getHeader(HttpHeaders_1.default.IF_NONE_MATCH);
if (!etag || !ifNoneMatch) {
return false;
}
etag = RequestUtil_1.default.padEtagIfNecessary(etag);
if (etag.startsWith('W/')) {
etag = etag.substring(2);
}
const match = (value) => {
const r = value.match(etagRegex);
return r && r[3] === etag;
};
const elements = ifNoneMatch instanceof Array ? ifNoneMatch : [ifNoneMatch];
this.notModified = !!elements.find(match);
return true;
}
/**
* 校验if-modified-since
*/
validateIfModifiedSince(lastModifiedTimestamp) {
const ifModifiedSince = RequestUtil_1.default.parseDataHeader(this.request, HttpHeaders_1.default.IF_MODIFIED_SINCE);
if (!ifModifiedSince || lastModifiedTimestamp < 0) {
return false;
}
const timestamp = this.normalizeTimestamp(lastModifiedTimestamp);
this.notModified = ifModifiedSince >= timestamp;
return true;
}
}
exports.default = HttpRequestValidation;