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

webdav

Package Overview
Dependencies
Maintainers
1
Versions
101
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

webdav - npm Package Compare versions

Comparing version 0.10.0 to 1.0.0-rc1

test/resources/webdav_testing_files/folder with spécial ch@r/test.txt

75

API.md
## Functions
<dl>
<dt><a href="#request">request(url, options)</a> ⇒ <code>Promise</code></dt>
<dd><p>Perform a request</p>
</dd>
<dt><a href="#setFetchMethod">setFetchMethod(fn)</a></dt>
<dd><p>Set the fetch method to use when making requests
Defaults to <code>node-fetch</code>. Setting it to <code>null</code> will reset it to <code>node-fetch</code>.</p>
</dd>
<dt><a href="#getQuota">getQuota([options])</a> ⇒ <code>null</code> | <code>Object</code></dt>
<dd><p>Get quota information</p>
</dd>
<dt><a href="#createWebDAVClient">createWebDAVClient(remoteURL)</a> ⇒ <code>Object</code></dt>

@@ -20,2 +30,39 @@ <dd><p>Create a webdav client interface</p>

<a name="request"></a>
## request(url, options) ⇒ <code>Promise</code>
Perform a request
**Kind**: global function
**Returns**: <code>Promise</code> - A promise that resolves with the result
| Param | Type | Description |
| --- | --- | --- |
| url | <code>String</code> | The URL to fetch |
| options | <code>Object</code> | Fetch options |
<a name="setFetchMethod"></a>
## setFetchMethod(fn)
Set the fetch method to use when making requests
Defaults to `node-fetch`. Setting it to `null` will reset it to `node-fetch`.
**Kind**: global function
| Param | Type | Description |
| --- | --- | --- |
| fn | <code>function</code> | Function to use - should perform like `fetch`. |
<a name="getQuota"></a>
## getQuota([options]) ⇒ <code>null</code> &#124; <code>Object</code>
Get quota information
**Kind**: global function
**Returns**: <code>null</code> &#124; <code>Object</code> - Returns null if failed, or an object with `used` and `available`
| Param | Type | Description |
| --- | --- | --- |
| [options] | <code>[OptionsHeadersAndFormat](#OptionsHeadersAndFormat)</code> | Options for the request |
<a name="createWebDAVClient"></a>

@@ -43,6 +90,6 @@

* [.createReadStream(remoteFilename, [options])](#ClientInterface.createReadStream) ⇒ <code>Readable</code>
* [.createWriteStream(remoteFilename, [options])](#ClientInterface.createWriteStream) ⇒ <code>Writeable</code>
* [.deleteFile(remotePath, [options])](#ClientInterface.deleteFile) ⇒ <code>Promise</code>
* [.getDirectoryContents(remotePath, [options])](#ClientInterface.getDirectoryContents) ⇒ <code>Promise.&lt;Array&gt;</code>
* [.getFileContents(remoteFilename, [options])](#ClientInterface.getFileContents) ⇒ <code>Promise.&lt;(Buffer\|String)&gt;</code>
* [.getFileStream(remoteFilename, [options])](#ClientInterface.getFileStream) ⇒ <code>Promise.&lt;Readable&gt;</code>
* [.moveFile(remotePath, targetRemotePath, [options])](#ClientInterface.moveFile) ⇒ <code>Promise</code>

@@ -78,2 +125,15 @@ * [.putFileContents(remoteFilename, data, [options])](#ClientInterface.putFileContents) ⇒ <code>Promise</code>

<a name="ClientInterface.createWriteStream"></a>
### ClientInterface.createWriteStream(remoteFilename, [options]) ⇒ <code>Writeable</code>
Create a writeable stream to a remote file
**Kind**: static method of <code>[ClientInterface](#ClientInterface)</code>
**Returns**: <code>Writeable</code> - A writeable stream
| Param | Type | Description |
| --- | --- | --- |
| remoteFilename | <code>String</code> | The file to write to |
| [options] | <code>[OptionsHeadersAndFormat](#OptionsHeadersAndFormat)</code> | Options for the request |
<a name="ClientInterface.deleteFile"></a>

@@ -118,15 +178,2 @@

<a name="ClientInterface.getFileStream"></a>
### ClientInterface.getFileStream(remoteFilename, [options]) ⇒ <code>Promise.&lt;Readable&gt;</code>
Get a readable stream of a remote file
**Kind**: static method of <code>[ClientInterface](#ClientInterface)</code>
**Returns**: <code>Promise.&lt;Readable&gt;</code> - A promise that resolves with a readable stream
| Param | Type | Description |
| --- | --- | --- |
| remoteFilename | <code>String</code> | The file to stream |
| [options] | <code>[OptionsHeadersAndFormat](#OptionsHeadersAndFormat)</code> | Options for the request |
<a name="ClientInterface.moveFile"></a>

@@ -133,0 +180,0 @@

8

package.json
{
"name": "webdav",
"version": "0.10.0",
"version": "1.0.0-rc1",
"description": "WebDAV client for NodeJS",

@@ -8,3 +8,3 @@ "main": "source/index.js",

"generate:docs": "jsdoc2md 'source/**/*.js' > API.md",
"test": "mocha -r test/specs/index.js test/specs/**/*.spec.js"
"test": "mocha -r test/specs/index.js test/specs/*.spec.js test/specs/integration/*.spec.js"
},

@@ -40,4 +40,6 @@ "repository": {

"mocha": "^3.1.0",
"rimraf": "^2.5.4"
"rimraf": "^2.5.4",
"sinon": "^2.3.5",
"wait-on": "^2.0.2"
}
}

@@ -41,6 +41,11 @@ # WebDAV client

#### createReadStream(remotePath _[, options]_)
Creates a readable stream on the remote path. Options is the same format as `getReadStream`.
Creates a readable stream on the remote path.
Returns a readable stream instance.
#### createWriteStream(remotePath _[, options]_)
Creates a writeable stream to a remote path.
Returns a writeable stream instance.
#### deleteFile(remotePath _[, options]_)

@@ -117,2 +122,17 @@ Delete a file or directory at `remotePath`.

#### getQuota(_[options]_)
Get quota information. Returns `null` upon failure or an object like so:
```json
{
"used": "12842",
"available": "512482001"
}
```
Both values are provided in bytes in string form. `available` may also be one of the following:
* `unknown`: The available space is unknown or not yet calculated
* `unlimited`: The space available is not limited by quotas
#### moveFile(remotePath, targetPath _[, options]_)

@@ -161,2 +181,11 @@ Move a file or directory from `remotePath` to `targetPath`.

### Overriding the built-in fetch function
Under the hood, `webdav-client` uses [`node-fetch`](https://github.com/bitinn/node-fetch) to perform requests. This can be overridden by running the following:
```js
// For example, use the `fetch` method in the browser:
const createWebDAVClient = require("webdav");
createWebDAVClient.setFetchMethod(window.fetch);
```
### Returned data structures

@@ -163,0 +192,0 @@

var deepmerge = require("deepmerge");
var responseHandlers = require("./response.js"),
fetch = require("./request.js");
fetch = require("./request.js").fetch;

@@ -6,0 +6,0 @@ module.exports = {

@@ -8,12 +8,46 @@ var xml2js = require("xml2js"),

var fetch = require("./request.js"),
var fetch = require("./request.js").fetch,
parsing = require("./parse.js"),
responseHandlers = require("./response.js");
var adapter = module.exports = {
function getFileStream(url, filePath, options) {
options = deepmerge({ headers: {} }, options || {});
if (typeof options.range === "object" && typeof options.range.start === "number") {
var rangeHeader = "bytes=" + options.range.start + "-";
if (typeof options.range.end === "number") {
rangeHeader += options.range.end;
}
options.headers.Range = rangeHeader;
}
return fetch(url + filePath, {
method: "GET",
headers: options.headers
})
.then(responseHandlers.handleResponseCode)
.then(function(res) {
return res.body;
});
}
function parseXMLBody(body) {
var parser = new xml2js.Parser({ ignoreAttrs: true });
return new Promise(function(resolve, reject) {
parser.parseString(body, function (err, result) {
if (err) {
return reject(err);
}
return resolve(result);
});
});
}
function toText(res) {
return res.text();
}
module.exports = {
createReadStream: function createReadStream(url, filePath, options) {
var outStream = new PassThroughStream();
adapter
.getFileStream(url, filePath, options)
getFileStream(url, filePath, options)
.then(function __handleStream(stream) {

@@ -76,18 +110,16 @@ stream.pipe(outStream);

getFileStream: function getFileStream(url, filePath, options) {
getQuota: function getQuota(url, options) {
options = deepmerge({ headers: {} }, options || {});
if (typeof options.range === "object" && typeof options.range.start === "number") {
var rangeHeader = "bytes=" + options.range.start + "-";
if (typeof options.range.end === "number") {
rangeHeader += options.range.end;
}
options.headers.Range = rangeHeader;
}
return fetch(url + filePath, {
method: "GET",
headers: options.headers
return fetch(url + "/", {
method: "PROPFIND",
headers: deepmerge(
{ Depth: 0 },
options.headers
)
})
.then(responseHandlers.handleResponseCode)
.then(function(res) {
return res.body;
.then(toText)
.then(parseXMLBody)
.then(function __processStats(result) {
return parsing.processQuota(result);
});

@@ -101,5 +133,3 @@ },

headers: deepmerge(
{
Depth: 1
},
{ Depth: 0 },
options.headers

@@ -109,20 +139,8 @@ )

.then(responseHandlers.handleResponseCode)
.then(function(res) {
return res.text();
.then(toText)
.then(parseXMLBody)
.then(function __processStats(result) {
var targetPath = itemPath.replace(/^\//, "");
return parsing.parseDirectoryLookup(targetPath, result, true);
})
.then(function(body) {
var parser = new xml2js.Parser({
ignoreAttrs: true
});
return new Promise(function(resolve, reject) {
parser.parseString(body, function (err, result) {
if (err) {
reject(err);
} else {
var targetPath = itemPath.replace(/^\//, "");
resolve(parsing.parseDirectoryLookup(targetPath, result, true));
}
});
});
})
.then(function(stats) {

@@ -129,0 +147,0 @@ return stats.shift();

@@ -63,2 +63,3 @@ var path = require("path");

.length;
dirPath = decodeURI(dirPath);
var filename = processDirectoryResultFilename(

@@ -112,2 +113,22 @@ dirPath,

function processQuota(result) {
var responseItem = null;
try {
var multistatus = getOne(result, ["d:multistatus", "D:multistatus", "multistatus"]),
responseItems = getOne(multistatus, ["d:response", "D:response", "response"]) || [];
responseItem = responseItems[0] || null;
} catch (e) {}
if (responseItem) {
var propstat = getOne(responseItem, ["d:propstat.0", "D:propstat.0", "propstat.0"]),
props = getOne(propstat, ["d:prop.0", "D:prop.0", "prop.0"]),
quotaUsed = processXMLStringValue(getOne(props, ["quota-used-bytes", "d:quota-used-bytes", "D:quota-used-bytes"])),
quotaAvail = processXMLStringValue(getOne(props, ["quota-available-bytes", "d:quota-available-bytes", "D:quota-available-bytes"]));
return {
used: quotaUsed,
available: translateDiskSpace(quotaAvail)
};
}
return null;
}
function processXMLStringValue(xmlVal) {

@@ -134,2 +155,16 @@ if (Array.isArray(xmlVal)) {

function translateDiskSpace(value) {
switch (value.toString()) {
case "-3":
return "unlimited";
case "-2":
/* falls-through */
case "-1":
// -1 is non-computed
return "unknown";
default:
return value;
}
}
module.exports = {

@@ -139,4 +174,6 @@

parseDirectoryLookup: processDirectoryResult
parseDirectoryLookup: processDirectoryResult,
processQuota: processQuota
};

@@ -1,5 +0,7 @@

var deepmerge = require("deepmerge");
var Stream = require("stream"),
PassThroughStream = Stream.PassThrough,
deepmerge = require("deepmerge");
var responseHandlers = require("./response.js"),
fetch = require("./request.js");
fetch = require("./request.js").fetch;

@@ -26,23 +28,27 @@ function getPutContentsDefaults() {

putFileContents: function putFileContents(url, filePath, data, options) {
options = deepmerge.all([
getPutContentsDefaults(),
{ headers: { "Content-Length": data.length } },
options || {}
]);
createWriteStream: function createWriteStream(url, filePath, options) {
options = deepmerge({ headers: {} }, options || {});
var writeStream = new PassThroughStream();
// if (typeof options.range === "object" && typeof options.range.start === "number") {
// var rangeHeader = "bytes=" + options.range.start + "-";
// if (typeof options.range.end === "number") {
// rangeHeader += options.range.end;
// }
// options.headers.Range = rangeHeader;
// }
if (options.overwrite === false) {
options.headers["If-None-Match"] = "*";
}
return fetch(url + filePath, {
method: "PUT",
headers: options.headers,
body: data
})
.then(responseHandlers.handleResponseCode);
fetch(url + filePath, {
method: "PUT",
headers: options.headers,
body: writeStream
});
return writeStream;
},
putTextContents: function putTextContents(url, filePath, text, options) {
putFileContents: function putFileContents(url, filePath, data, options) {
options = deepmerge.all([
getPutContentsDefaults(),
{ headers: { "Content-Length": text.length } },
{ headers: { "Content-Length": data.length } },
options || {}

@@ -56,3 +62,3 @@ ]);

headers: options.headers,
body: text
body: data
})

@@ -59,0 +65,0 @@ .then(responseHandlers.handleResponseCode);

var nodeFetch = require("node-fetch");
var fetch = nodeFetch;
var fetchMethod = nodeFetch;
// // For some reason window.fetch doesn't work in some cases
// if (typeof window === "object" && typeof window.fetch === "function") {
// fetch = window.fetch;
// }
/**
* Perform a request
* @param {String} url The URL to fetch
* @param {Object} options Fetch options
* @returns {Promise} A promise that resolves with the result
*/
function request(url, options) {
return fetchMethod(url, options);
};
module.exports = function request(url, options) {
return fetch(url, options);
/**
* Set the fetch method to use when making requests
* Defaults to `node-fetch`. Setting it to `null` will reset it to `node-fetch`.
* @param {Function} fn Function to use - should perform like `fetch`.
*/
function setFetchMethod(fn) {
fetchMethod = fn || nodeFetch;
}
module.exports = {
fetch: request,
setFetchMethod: setFetchMethod
};

@@ -74,2 +74,17 @@ var deepmerge = require("deepmerge");

/**
* Create a writeable stream to a remote file
* @param {String} remoteFilename The file to write to
* @param {OptionsHeadersAndFormat=} options Options for the request
* @memberof ClientInterface
* @returns {Writeable} A writeable stream
*/
createWriteStream: function createWriteStream(remoteFilename, options) {
var putOptions = deepmerge(
baseOptions,
options || {}
);
return putAdapter.createWriteStream(__url, remoteFilename, putOptions);
},
/**
* Delete a remote file

@@ -126,9 +141,7 @@ * @param {String} remotePath The remote path to delete

/**
* Get a readable stream of a remote file
* @param {String} remoteFilename The file to stream
* Get quota information
* @param {OptionsHeadersAndFormat=} options Options for the request
* @memberof ClientInterface
* @returns {Promise.<Readable>} A promise that resolves with a readable stream
* @returns {null|Object} Returns null if failed, or an object with `used` and `available`
*/
getFileStream: function getFileStream(remoteFilename, options) {
getQuota: function getQuota(options) {
var getOptions = deepmerge(

@@ -138,3 +151,3 @@ baseOptions,

);
return getAdapter.getFileStream(__url, remoteFilename, getOptions);
return getAdapter.getQuota(__url, getOptions);
},

@@ -171,9 +184,3 @@

);
putOptions.format = putOptions.format || "binary";
if (["binary", "text"].indexOf(putOptions.format) < 0) {
throw new Error("Unknown format: " + putOptions.format);
}
return (putOptions.format === "text") ?
putAdapter.putTextContents(__url, remoteFilename, data, putOptions) :
putAdapter.putFileContents(__url, remoteFilename, data, putOptions);
return putAdapter.putFileContents(__url, remoteFilename, data, putOptions);
},

@@ -180,0 +187,0 @@

@@ -1,2 +0,3 @@

var factory = require("./clientFactory.js");
var factory = require("./clientFactory.js"),
setFetchMethod = require("./adapter/request.js").setFetchMethod;

@@ -14,2 +15,4 @@ /**

createWebDAVClient.setFetchMethod = setFetchMethod;
module.exports = createWebDAVClient;

@@ -89,2 +89,26 @@ var path = require("path");

it("streams portions (ranges) of a remote file", function() {
var stream1 = getAdapter.createReadStream(SERVER_URL, "/gem.png", { range: { start: 0, end: 199 } }),
stream2 = getAdapter.createReadStream(SERVER_URL, "/gem.png", { range: { start: 200, end: 278 } })
return Promise
.all([
streamToBuffer(stream1),
streamToBuffer(stream2)
])
.then(function(buffers) {
var part1 = buffers.shift(),
part2 = buffers.shift();
expect(part1.length).to.equal(200);
expect(part2.length).to.equal(79);
});
});
it("streams a partial file when only start is provided", function() {
var stream = getAdapter.createReadStream(SERVER_URL, "/gem.png", { range: { start: 200 } });
return streamToBuffer(stream)
.then(function(buff) {
expect(buff.length).to.equal(79);
});
});
});

@@ -98,3 +122,3 @@

.then(function(contents) {
expect(contents.length).to.equal(2);
expect(contents.length).to.equal(3);
});

@@ -123,2 +147,9 @@ });

});
it("gets all objects in directory with special character", function() {
return getAdapter
.getDirectoryContents(SERVER_URL, encodeURI("/folder with spécial ch@r"))
.then(function(contents) {
expect(contents.length).to.equal(1);
});
});

@@ -140,46 +171,20 @@ });

describe("getFileStream", function() {
describe("getQuota", function() {
it("streams contents of a remote file", function() {
it("gets a valid used value", function() {
return getAdapter
.getFileStream(SERVER_URL, "/gem.png")
.then(function(stream) {
expect(stream instanceof ReadableStream).to.be.true;
return streamToBuffer(stream);
})
.then(function(buff) {
expect(buff.length).to.equal(279);
.getQuota(SERVER_URL)
.then(function(quota) {
expect(parseInt(quota.used, 10)).to.be.above(-1);
});
});
it("streams portions (ranges) of a remote file", function() {
return Promise
.all([
getAdapter.getFileStream(SERVER_URL, "/gem.png", { range: { start: 0, end: 199 } }),
getAdapter.getFileStream(SERVER_URL, "/gem.png", { range: { start: 200, end: 278 } })
])
.then(function(streams) {
var part1 = streams.shift(),
part2 = streams.shift();
return Promise.all([
streamToBuffer(part1),
streamToBuffer(part2)
]);
})
.then(function(buffers) {
var part1 = buffers.shift(),
part2 = buffers.shift();
expect(part1.length).to.equal(200);
expect(part2.length).to.equal(79);
});
});
it("streams a partial file when only start is provided", function() {
it("gets a valid available value", function() {
return getAdapter
.getFileStream(SERVER_URL, "/gem.png", { range: { start: 200 } })
.then(function(stream) {
return streamToBuffer(stream);
})
.then(function(buff) {
expect(buff.length).to.equal(79);
.getQuota(SERVER_URL)
.then(function(quota) {
var avail = quota.available;
if (["unknown", "unlimited"].indexOf(avail) < 0) {
expect(parseInt(avail, 10)).to.be.above(-1);
}
});

@@ -186,0 +191,0 @@ });

@@ -6,3 +6,4 @@ var path = require("path"),

directoryExists = require("directory-exists").sync,
rimraf = require("rimraf").sync;
rimraf = require("rimraf").sync,
waitOn = require("wait-on");

@@ -18,2 +19,20 @@ var createServer = require(__dirname + "/../resources/webdav-server.js"),

function waitOnFile(filename) {
return new Promise(function(resolve, reject) {
waitOn(
{
resources: [ filename ],
interval: 50,
timeout: 500,
window: 0
}, function(err) {
if (err) {
return reject(err);
}
return resolve();
}
);
});
}
describe("adapter:put", function() {

@@ -57,2 +76,26 @@

describe("createWriteStream", function() {
before(function() {
if (fileExists(TARGET_FILE)) {
throw new Error("Testing file existed when it shouldn't have");
}
});
it("writes the file to the remote", function() {
var writeStream = putAdapter.createWriteStream("http://localhost:9999", "/gem2.png"),
readStream = fs.createReadStream(TARGET_FILE_ORIGINAL);
return new Promise(function(resolve, reject) {
writeStream.on("end", function() {
// stupid stream needs time to close probably..
waitOnFile(TARGET_FILE)
.then(resolve, reject);
});
writeStream.on("error", reject);
readStream.pipe(writeStream);
});
});
});
describe("putFileContents", function() {

@@ -108,12 +151,2 @@

});
describe("putTextContents", function() {
before(function() {
if (fileExists(TARGET_TEXT_FILE)) {
throw new Error("Testing file existed when it shouldn't have");
}
});
it("puts the text file correctly in the remote directory", function() {

@@ -123,3 +156,3 @@ var text = " This is the first line, \n" +

return putAdapter
.putTextContents("http://localhost:9999", "/written.txt", text)
.putFileContents("http://localhost:9999", "/written.txt", text)
.then(function() {

@@ -133,3 +166,2 @@ var readText = fs.readFileSync(TARGET_TEXT_FILE, "utf8");

});

@@ -1,4 +0,7 @@

var expect = require("chai").expect;
var expect = require("chai").expect,
sinon = require("sinon");
Object.assign(global, {
expect: expect
expect: expect,
sinon: sinon
});
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