Skip to content

Commit

Permalink
Added the a parser for the 'If' header
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienCastex committed May 23, 2017
1 parent c4d3ace commit e4e2208
Show file tree
Hide file tree
Showing 3 changed files with 299 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/helper/IfParser.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { IResource, ReturnCallback } from '../resource/IResource';
import { MethodCallArgs } from '../server/MethodCallArgs';
export declare function extractOneToken(ifHeader: string): string;
export declare function parseIfHeader(ifHeader: string): (arg: MethodCallArgs, r: IResource, callback: ReturnCallback<boolean>) => void;
128 changes: 128 additions & 0 deletions lib/helper/IfParser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var IResource_1 = require("../resource/IResource");
var url = require("url");
function NoLock() {
return function (r, callback) {
r.getLocks(function (e, locks) {
callback(e, locks ? locks.length === 0 : false);
});
};
}
function Token(token) {
return function (r, callback) {
r.getLock(token, function (e, lock) {
callback(e, !!lock && !e);
});
};
}
function Tag(tag) {
return function (r, callback) {
r.lastModifiedDate(function (e, lastModifiedDate) {
callback(e, !e && IResource_1.ETag.createETag(lastModifiedDate) === tag);
});
};
}
function Not(filter) {
return function (r, callback) {
filter(r, function (e, v) {
callback(e, !v);
});
};
}
function parseInternal(group) {
var rex = /((not)|<([^>]+)>|\[([^\]]+)\]|<(DAV:no-lock)>)/ig;
var match = rex.exec(group);
var isNot = false;
var andArray = [];
function add(filter) {
andArray.push(isNot ? Not(filter) : filter);
isNot = false;
}
while (match) {
if (match[2]) {
isNot = true;
}
else if (match[3]) {
add(Token(match[3]));
}
else if (match[4]) {
add(Tag(match[4]));
}
else if (match[5]) {
add(NoLock());
}
match = rex.exec(group);
}
if (andArray.length)
return function (r, callback) { return callback(null, true); };
return function (r, callback) {
var nb = andArray.length;
function done(error, result) {
if (nb <= 0)
return;
if (error) {
nb = -1;
callback(error, false);
return;
}
--nb;
if (nb === 0 || !result) {
nb = -1;
callback(null, result);
}
}
andArray.forEach(function (a) { return a(r, done); });
};
}
function extractOneToken(ifHeader) {
var match = /^[ ]*\([ ]*<([^>]+)>[ ]*\)[ ]*$/.exec(ifHeader);
if (!match)
return null;
else
return match[1];
}
exports.extractOneToken = extractOneToken;
function parseIfHeader(ifHeader) {
var rex = /(?:<([^>]+)>)?\s*\(([^\)]+)\)/g;
var match = rex.exec(ifHeader);
var orArray = [];
var oldPath = undefined;
while (match) {
if (match[1])
oldPath = url.parse(match[1]).path;
orArray.push({
path: oldPath,
actions: parseInternal(match[2])
});
match = rex.exec(ifHeader);
}
if (orArray.length)
return function (arg, r, callback) { return callback(null, true); };
return function (arg, r, callback) {
var nb = orArray.length;
function done(error, result) {
if (nb <= 0)
return;
if (error) {
nb = -1;
callback(error, false);
return;
}
--nb;
if (nb === 0 || result) {
nb = -1;
callback(null, result);
}
}
orArray.forEach(function (a) {
if (!a.path)
a.actions(r, done);
else
arg.server.getResourceFromPath(a.path, function (e, resource) {
a.actions(resource, done);
});
});
};
}
exports.parseIfHeader = parseIfHeader;
167 changes: 167 additions & 0 deletions src/helper/IfParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { IResource, ReturnCallback, ETag } from '../resource/IResource'
import { MethodCallArgs } from '../server/MethodCallArgs'
import { Errors } from '../Errors'
import * as url from 'url'

type FnReturn = ReturnCallback<boolean>

function NoLock()
{
return function(r : IResource, callback : FnReturn) {
r.getLocks((e, locks) => {
callback(e, locks ? locks.length === 0 : false);
})
}
}

function Token(token : string)
{
return function(r : IResource, callback : FnReturn) {
r.getLock(token, (e, lock) => {
callback(e, !!lock && !e);
})
}
}

function Tag(tag : string)
{
return function(r : IResource, callback : FnReturn) {
r.lastModifiedDate((e, lastModifiedDate) => {
callback(e, !e && ETag.createETag(lastModifiedDate) === tag);
})
}
}

function Not(filter)
{
return function(r : IResource, callback : FnReturn) {
filter(r, (e, v) => {
callback(e, !v);
})
}
}

function parseInternal(group : string)
{
const rex = /((not)|<([^>]+)>|\[([^\]]+)\]|<(DAV:no-lock)>)/ig;
let match = rex.exec(group);

let isNot = false;
const andArray = [];
function add(filter)
{
andArray.push(isNot ? Not(filter) : filter);
isNot = false;
}

while(match)
{
if(match[2])
{ // not
isNot = true;
}
else if(match[3])
{ // lock-token
add(Token(match[3]));
}
else if(match[4])
{ // tag
add(Tag(match[4]));
}
else if(match[5])
{ // DAV:no-lock
add(NoLock());
}
match = rex.exec(group);
}

if(andArray.length)
return (r, callback) => callback(null, true);

return function(r : IResource, callback : FnReturn) {
let nb = andArray.length;
function done(error, result)
{
if(nb <= 0)
return;
if(error)
{
nb = -1;
callback(error, false);
return;
}
--nb;
if(nb === 0 || !result)
{
nb = -1;
callback(null, result);
}
}

andArray.forEach((a) => a(r, done));
};
}

export function extractOneToken(ifHeader : string)
{
const match = /^[ ]*\([ ]*<([^>]+)>[ ]*\)[ ]*$/.exec(ifHeader);
if(!match)
return null;
else
return match[1];
}

export function parseIfHeader(ifHeader : string)
{
const rex = /(?:<([^>]+)>)?\s*\(([^\)]+)\)/g;
let match = rex.exec(ifHeader);

const orArray = [];
let oldPath = undefined;

while(match)
{
if(match[1])
oldPath = url.parse(match[1]).path;

orArray.push({
path: oldPath,
actions: parseInternal(match[2])
})

match = rex.exec(ifHeader);
}

if(orArray.length)
return (arg : MethodCallArgs, r : IResource, callback : ReturnCallback<boolean>) => callback(null, true);

return function(arg : MethodCallArgs, r : IResource, callback : ReturnCallback<boolean>) {
let nb = orArray.length;
function done(error, result)
{
if(nb <= 0)
return;
if(error)
{
nb = -1;
callback(error, false);
return;
}
--nb;
if(nb === 0 || result)
{
nb = -1;
callback(null, result);
}
}

orArray.forEach((a) => {
if(!a.path)
a.actions(r, done);
else
arg.server.getResourceFromPath(a.path, (e, resource) => {
a.actions(resource, done);
});
})
}
}

0 comments on commit e4e2208

Please sign in to comment.