Skip to content

Commit

Permalink
Use body-parser content-types for determining when to write binary or…
Browse files Browse the repository at this point in the history
… text data.
  • Loading branch information
coddingtonbear committed Dec 23, 2023
1 parent b2babcb commit 9385a94
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 45 deletions.
9 changes: 1 addition & 8 deletions docs/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ paths:
description: |
Creates a new file in your vault or updates the content of an existing one if the specified file already exists.
requestBody:
description: file or Content of the file you would like to upload.
description: Content of the file you would like to upload.
required: true
content:
'text/markdown':
Expand All @@ -358,13 +358,6 @@ paths:
# This is my document
something else here
'multipart/form-data':
schema:
type: object
example: |
{
"file": [binary file object]
}
'*/*':
schema:
type: string
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"@types/jest": "^27.4.0",
"@types/json-logic-js": "^1.2.1",
"@types/mime-types": "^2.1.1",
"@types/multer": "^1.4.11",
"@types/node": "^16.11.6",
"@types/node-forge": "^1.0.0",
"@types/supertest": "^2.0.11",
Expand All @@ -30,7 +29,7 @@
"builtin-modules": "^3.2.0",
"esbuild": "0.13.12",
"jest": "^26",
"obsidian": "latest",
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
"supertest": "^6.2.2",
"swagger-ui-cli": "^0.10.0",
"ts-jest": "26.5.6",
Expand All @@ -46,7 +45,6 @@
"matcher": "^5.0.0",
"mime-types": "^2.1.35",
"minimatch": "^5.0.1",
"multer": "^1.4.5-lts.1",
"node-forge": "^1.2.1",
"obsidian-daily-notes-interface": "^0.9.4",
"obsidian-dataview": "^0.5.47",
Expand Down
21 changes: 15 additions & 6 deletions src/requestHandler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,18 +226,27 @@ describe("requestHandler", () => {
test("acceptable binary content", async () => {
const arbitraryFilePath = "test.png";
const arbitraryBytes = "bytes"; // mock a picture binary
const file = Buffer.from(arbitraryBytes)

await request(server)
.put(`/vault/${arbitraryFilePath}`)
.set('Content-Type', 'multipart/form-data')
.set("Content-Type", "application/octet-stream")
.set("Authorization", `Bearer ${API_KEY}`)
.attach('file', file,arbitraryFilePath)
.send(arbitraryBytes)
.expect(204);

expect(app.vault.adapter._writeBinary[0]).toEqual(arbitraryFilePath);
const data = app.vault.adapter._writeBinary[1];
expect(Buffer.isBuffer(data) || data instanceof ArrayBuffer).toEqual(true);
expect(app.vault.adapter._writeBinary[0]).toEqual(arbitraryFilePath);
const data = app.vault.adapter._writeBinary[1];
console.log(data);
expect(Buffer.isBuffer(data) || data instanceof ArrayBuffer).toEqual(
true
);
// We won't be able to convert the incoming data
// to bytes with this mechanism in a _normal_
// situation because those bytes won't be encodable
// as ASCII, but we can do this here because we're
// lying about the incoming content type above
const decoder = new TextDecoder();
expect(decoder.decode(data)).toEqual(arbitraryBytes);
});

test("non-bytes content", async () => {
Expand Down
40 changes: 12 additions & 28 deletions src/requestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import {
apiVersion,
App,
CachedMetadata,
Command,
DataWriteOptions,
Command,
PluginManifest,
prepareSimpleSearch,
TFile,
Expand All @@ -21,7 +20,6 @@ import responseTime from "response-time";
import queryString from "query-string";
import WildcardRegexp from "glob-to-regexp";
import path from "path";
import multer from 'multer'

import {
CannedResponse,
Expand All @@ -34,23 +32,14 @@ import {
SearchJsonResponseItem,
SearchResponseItem,
} from "./types";
import { findHeadingBoundary, getSplicePosition } from "./utils";
import { findHeadingBoundary, getSplicePosition, toArrayBuffer } from "./utils";
import {
CERT_NAME,
ContentTypes,
ERROR_CODE_MESSAGES,
MaximumRequestSize,
} from "./constants";

function toArrayBuffer(arr: Uint8Array | ArrayBuffer | DataView): ArrayBufferLike {
if (arr instanceof Uint8Array) {
return arr.buffer;
}
if (arr instanceof DataView) {
return arr.buffer;
}
return arr;
}
export default class RequestHandler {
app: App;
api: express.Express;
Expand Down Expand Up @@ -287,18 +276,17 @@ export default class RequestHandler {
// the folder/file already exists, but we don't care
}

await this._adapterWrite(filepath,req.file?.buffer || req.body)
this.returnCannedResponse(res, { statusCode: 204 });
return;
}

async _adapterWrite(file: TFile | string, data: string | ArrayBuffer | Uint8Array, options?: DataWriteOptions) {
const path = file instanceof TFile ? file.path : file;
if (typeof (data) === "string") {
return this.app.vault.adapter.write(path, data, options)
if (typeof req.body === "string") {
await this.app.vault.adapter.write(filepath, req.body);
} else {
return this.app.vault.adapter.writeBinary(path, toArrayBuffer(data), options)
await this.app.vault.adapter.writeBinary(
filepath,
toArrayBuffer(req.body)
);
}

this.returnCannedResponse(res, { statusCode: 204 });
return;
}

async vaultPut(req: express.Request, res: express.Response): Promise<void> {
Expand Down Expand Up @@ -1046,14 +1034,10 @@ export default class RequestHandler {
.post(this.activeFilePost.bind(this))
.delete(this.activeFileDelete.bind(this));

const storage = multer.memoryStorage();
const upload = multer({
storage: storage
})
this.api
.route("/vault/(.*)")
.get(this.vaultGet.bind(this))
.put([upload.single('file'),this.vaultPut.bind(this)])
.put(this.vaultPut.bind(this))
.patch(this.vaultPatch.bind(this))
.post(this.vaultPost.bind(this))
.delete(this.vaultDelete.bind(this));
Expand Down
18 changes: 18 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,21 @@ export function getSplicePosition(
}
return splicePosition;
}

export function toArrayBuffer(
arr: Uint8Array | ArrayBuffer | DataView | object
): ArrayBufferLike {
if (arr instanceof Uint8Array) {
return arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength);
}
if (arr instanceof DataView) {
return arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength);
}
if (arr instanceof ArrayBuffer) {
return arr;
}
// If we've made it this far, we probably have a
// parsed JSON object
const encoder = new TextEncoder();
return encoder.encode(JSON.stringify(arr)).buffer;
}

0 comments on commit 9385a94

Please sign in to comment.