From 71c7073624fb59d06eb639b0566d4a30d90df38c Mon Sep 17 00:00:00 2001 From: Adrien Castex Date: Thu, 25 May 2017 16:05:22 +0200 Subject: [PATCH] Added the ability to switch to the chunked version of a command (method) when possible --- lib/server/MethodCallArgs.d.ts | 2 +- lib/server/WebDAVRequest.d.ts | 8 +++- lib/server/WebDAVServer.d.ts | 2 +- lib/server/WebDAVServer.js | 53 +++++++++++++++++++------- src/server/MethodCallArgs.ts | 2 +- src/server/WebDAVRequest.ts | 8 +++- src/server/WebDAVServer.ts | 68 ++++++++++++++++++++++++++-------- 7 files changed, 107 insertions(+), 36 deletions(-) diff --git a/lib/server/MethodCallArgs.d.ts b/lib/server/MethodCallArgs.d.ts index 8eea80a7..f4e743b7 100644 --- a/lib/server/MethodCallArgs.d.ts +++ b/lib/server/MethodCallArgs.d.ts @@ -17,7 +17,7 @@ export declare class MethodCallArgs { host: string; path: FSPath; uri: string; - data: string; + data: Int8Array; user: IUser; protected constructor(server: WebDAVServer, request: http.IncomingMessage, response: http.ServerResponse, exit: () => void, callback: () => void); static create(server: WebDAVServer, request: http.IncomingMessage, response: http.ServerResponse, callback: (error: Error, mca: MethodCallArgs) => void): void; diff --git a/lib/server/WebDAVRequest.d.ts b/lib/server/WebDAVRequest.d.ts index b157a83b..f9de4c81 100644 --- a/lib/server/WebDAVRequest.d.ts +++ b/lib/server/WebDAVRequest.d.ts @@ -1,7 +1,11 @@ -import MethodCallArgs from './MethodCallArgs'; +/// +import { MethodCallArgs } from './MethodCallArgs'; +import { HTTPError } from '../Errors'; export { MethodCallArgs } from './MethodCallArgs'; export { HTTPCodes } from './HTTPCodes'; +export declare type ChunkOnDataCallback = (chunk: Buffer, isFirst: boolean, isLast: boolean) => void; +export declare type StartChunkedCallback = (error: HTTPError, onData: ChunkOnDataCallback) => void; export interface WebDAVRequest { (arg: MethodCallArgs, callback: () => void): void; - chunked?: boolean; + startChunked?: (arg: MethodCallArgs, callback: StartChunkedCallback) => void; } diff --git a/lib/server/WebDAVServer.d.ts b/lib/server/WebDAVServer.d.ts index afb06c3f..6b42ed79 100644 --- a/lib/server/WebDAVServer.d.ts +++ b/lib/server/WebDAVServer.d.ts @@ -1,7 +1,7 @@ /// +import { MethodCallArgs, WebDAVRequest } from './WebDAVRequest'; import { WebDAVServerOptions } from './WebDAVServerOptions'; import { SerializedObject } from '../manager/ISerializer'; -import { MethodCallArgs, WebDAVRequest } from './WebDAVRequest'; import { IResource, ReturnCallback } from '../resource/IResource'; import { HTTPAuthentication } from '../user/authentication/HTTPAuthentication'; import { IPrivilegeManager } from '../user/privilege/IPrivilegeManager'; diff --git a/lib/server/WebDAVServer.js b/lib/server/WebDAVServer.js index 6587a5c2..919199b7 100644 --- a/lib/server/WebDAVServer.js +++ b/lib/server/WebDAVServer.js @@ -1,8 +1,8 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +var WebDAVRequest_1 = require("./WebDAVRequest"); var WebDAVServerOptions_1 = require("./WebDAVServerOptions"); var ISerializer_1 = require("../manager/ISerializer"); -var WebDAVRequest_1 = require("./WebDAVRequest"); var FSManager_1 = require("../manager/FSManager"); var Errors_1 = require("../Errors"); var Commands_1 = require("./commands/Commands"); @@ -182,32 +182,59 @@ var WebDAVServer = (function () { res.end(); return; } - if (!method.chunked) { - var data_1 = ''; + base.exit = function () { + base.response.end(); + _this.invokeAfterRequest(base, null); + }; + if (!_this.options.canChunk || !method.startChunked || base.contentLength <= 0) { var go_1 = function () { - base.data = data_1; _this.invokeBeforeRequest(base, function () { - base.exit = function () { - res.end(); - _this.invokeAfterRequest(base, null); - }; method(base, base.exit); }); }; - if (base.contentLength === 0) { + if (base.contentLength <= 0) { + base.data = new Buffer(0); go_1(); } else { + var data_1 = new Buffer(base.contentLength); + var index_1 = 0; req.on('data', function (chunk) { - data_1 += chunk.toString(); - if (data_1.length >= base.contentLength) { - if (data_1.length > base.contentLength) - data_1 = data_1.substring(0, base.contentLength); + if (chunk.constructor === String) + chunk = new Buffer(chunk); + for (var i = 0; i < chunk.length && index_1 < data_1.length; ++i, ++index_1) + data_1[index_1] = chunk[i]; + if (index_1 >= base.contentLength) { + base.data = data_1; go_1(); } }); } } + else { + _this.invokeBeforeRequest(base, function () { + _this.invokeBeforeRequest(base, function () { + method.startChunked(base, function (error, onData) { + if (error) { + base.setCode(error.HTTPCode); + base.exit(); + return; + } + if (!onData) { + base.exit(); + return; + } + var size = 0; + req.on('data', function (chunk) { + if (chunk.constructor === String) + chunk = new Buffer(chunk); + size += chunk.length; + onData(chunk, size === chunk.length, size >= base.contentLength); + }); + }); + }); + }); + } }); }); } diff --git a/src/server/MethodCallArgs.ts b/src/server/MethodCallArgs.ts index bb86523e..e332d468 100644 --- a/src/server/MethodCallArgs.ts +++ b/src/server/MethodCallArgs.ts @@ -18,7 +18,7 @@ export class MethodCallArgs path : FSPath uri : string - data : string + data : Int8Array user : IUser protected constructor( diff --git a/src/server/WebDAVRequest.ts b/src/server/WebDAVRequest.ts index 1586c5e2..fcc3e210 100644 --- a/src/server/WebDAVRequest.ts +++ b/src/server/WebDAVRequest.ts @@ -1,17 +1,21 @@ import { IResource, ReturnCallback } from '../resource/IResource' +import { MethodCallArgs } from './MethodCallArgs' import { WebDAVServer } from '../server/WebDAVServer' +import { HTTPError } from '../Errors' import { FSPath } from '../manager/FSManager' import HTTPCodes from './HTTPCodes' -import MethodCallArgs from './MethodCallArgs' import * as http from 'http' import * as url from 'url' export { MethodCallArgs } from './MethodCallArgs' export { HTTPCodes } from './HTTPCodes' +export type ChunkOnDataCallback = (chunk : Buffer, isFirst : boolean, isLast : boolean) => void +export type StartChunkedCallback = (error : HTTPError, onData : ChunkOnDataCallback) => void + export interface WebDAVRequest { (arg : MethodCallArgs, callback : () => void) : void - chunked ?: boolean + startChunked ?: (arg : MethodCallArgs, callback : StartChunkedCallback) => void } diff --git a/src/server/WebDAVServer.ts b/src/server/WebDAVServer.ts index dd63c512..807dace8 100644 --- a/src/server/WebDAVServer.ts +++ b/src/server/WebDAVServer.ts @@ -1,15 +1,15 @@ +import { HTTPCodes, MethodCallArgs, WebDAVRequest, ChunkOnDataCallback } from './WebDAVRequest' import { WebDAVServerOptions, setDefaultServerOptions } from './WebDAVServerOptions' import { SerializedObject, unserialize, serialize } from '../manager/ISerializer' -import { HTTPCodes, MethodCallArgs, WebDAVRequest } from './WebDAVRequest' import { IResource, ReturnCallback } from '../resource/IResource' import { FakePrivilegeManager } from '../user/privilege/FakePrivilegeManager' import { HTTPAuthentication } from '../user/authentication/HTTPAuthentication' import { IPrivilegeManager } from '../user/privilege/IPrivilegeManager' import { SimpleUserManager } from '../user/simple/SimpleUserManager' import { FSManager, FSPath } from '../manager/FSManager' +import { Errors, HTTPError } from '../Errors' import { RootResource } from '../resource/std/RootResource' import { IUserManager } from '../user/IUserManager' -import { Errors } from '../Errors' import Commands from './commands/Commands' import * as http from 'http' @@ -273,39 +273,75 @@ export class WebDAVServer return; } - if(!method.chunked) + base.exit = () => + { + base.response.end(); + this.invokeAfterRequest(base, null); + }; + + if(!this.options.canChunk || !method.startChunked || base.contentLength <= 0) { - let data = ''; const go = () => { - base.data = data; this.invokeBeforeRequest(base, () => { - base.exit = () => - { - res.end(); - this.invokeAfterRequest(base, null); - }; method(base, base.exit); }) } - - if(base.contentLength === 0) + + if(base.contentLength <= 0) { + base.data = new Buffer(0); go(); } else { + const data = new Buffer(base.contentLength); + let index = 0; req.on('data', (chunk) => { - data += chunk.toString(); - if(data.length >= base.contentLength) + if(chunk.constructor === String) + chunk = new Buffer(chunk as string); + + for(let i = 0; i < chunk.length && index < data.length; ++i, ++index) + data[index] = (chunk as Buffer)[i]; + + if(index >= base.contentLength) { - if(data.length > base.contentLength) - data = data.substring(0, base.contentLength); + base.data = data; go(); } }); } } + else + { + this.invokeBeforeRequest(base, () => { + this.invokeBeforeRequest(base, () => { + method.startChunked(base, (error : HTTPError, onData : ChunkOnDataCallback) => { + if(error) + { + base.setCode(error.HTTPCode); + base.exit(); + return; + } + + if(!onData) + { + base.exit(); + return; + } + + let size = 0; + req.on('data', (chunk) => { + if(chunk.constructor === String) + chunk = new Buffer(chunk as string); + size += chunk.length; + + onData(chunk as Buffer, size === chunk.length, size >= base.contentLength); + }); + }); + }) + }) + } }) }) }