Add some sources validation
This commit is contained in:
@@ -20,6 +20,8 @@ import {
|
||||
isURL,
|
||||
} from './_source-checkers'
|
||||
|
||||
export const DEFAULT_FILENAME = 'index.html'
|
||||
|
||||
/**
|
||||
* Convert any possible source to tuples array
|
||||
*/
|
||||
@@ -30,14 +32,14 @@ export const toTuples = (source: Source, recursive = false): TupleSource[] => {
|
||||
// if single file uri
|
||||
if (isFileUri(source)) {
|
||||
return !recursive && extname(source) === '.html'
|
||||
? [['index.html', source]] // single file uri and not inside recursion -> assume this is 'index.html'
|
||||
? [[DEFAULT_FILENAME, source]] // single file uri and not inside recursion -> assume this is 'index.html'
|
||||
: [[basename(source), source]] // if inside recursion or file is not .html -> just get name from file uri
|
||||
}
|
||||
|
||||
// single string or buffer
|
||||
if (isString(source) || isBuffer(source)) {
|
||||
// just assume it is 'index.html', as most useful and common case
|
||||
return [['index.html', source]]
|
||||
return [[DEFAULT_FILENAME, source]]
|
||||
}
|
||||
|
||||
// if single stream
|
||||
@@ -47,11 +49,11 @@ export const toTuples = (source: Source, recursive = false): TupleSource[] => {
|
||||
// https://nodejs.org/api/fs.html#fs_readstream_path
|
||||
const name = basename(String(source.path))
|
||||
return !recursive && extname(name) === '.html'
|
||||
? [['index.html', source]] // single file stream and not inside recursion -> assume this is 'index.html'
|
||||
? [[DEFAULT_FILENAME, source]] // single file stream and not inside recursion -> assume this is 'index.html'
|
||||
: [[name, source]] // if inside recursion or file is not .html -> just get name from file uri
|
||||
} else {
|
||||
// some strange, not file stream -> just assume it is 'index.html'
|
||||
return [['index.html', source]]
|
||||
return [[DEFAULT_FILENAME, source]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ export type Source =
|
||||
| PlainSource
|
||||
| TupleSource
|
||||
| ObjectSource
|
||||
| Array<PlainSource | TupleSource | ObjectSource>
|
||||
| Iterable<PlainSource | TupleSource | ObjectSource>
|
||||
export type TupleStreamsSource = [string, NodeJS.ReadableStream]
|
||||
|
||||
|
||||
+14
-2
@@ -37,8 +37,20 @@ export function post(
|
||||
if (res.statusCode === 200) {
|
||||
resolve(res)
|
||||
} else {
|
||||
res.resume() // ignore response body
|
||||
reject(new Error(res.statusCode + ' ' + res.statusMessage))
|
||||
let error = res.statusCode + ' ' + res.statusMessage
|
||||
|
||||
// something is wrong, get error message from Gotenberg
|
||||
const chunks: Buffer[] = []
|
||||
res.on('data', (chunk: Buffer) => chunks.push(chunk))
|
||||
res.on('end', () => {
|
||||
try {
|
||||
error +=
|
||||
' (' + JSON.parse(Buffer.concat(chunks).toString()).message + ')'
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
reject(new Error(error))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
+45
-2
@@ -6,7 +6,7 @@ import {
|
||||
TupleStreamsSource,
|
||||
TypedRequest,
|
||||
} from './_types'
|
||||
import { toStreams } from './_source-converters'
|
||||
import { DEFAULT_FILENAME, toStreams } from './_source-converters'
|
||||
|
||||
/**
|
||||
* Helper function to convert fields and files to form data
|
||||
@@ -34,6 +34,49 @@ const formdata = (fields: RequestFields, files: TupleStreamsSource[]) => {
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate sources' file names
|
||||
*/
|
||||
function validateSources(
|
||||
type: RequestType,
|
||||
sources: TupleStreamsSource[]
|
||||
): TupleStreamsSource[] {
|
||||
const filenames = sources.map(source => source[0])
|
||||
|
||||
// check for duplicates
|
||||
const duplicates = filenames.filter(
|
||||
(name, index, arr) => arr.indexOf(name) !== index
|
||||
)
|
||||
if (duplicates.length > 0) {
|
||||
throw new Error(
|
||||
`There are duplicates in file names: ${duplicates.join(',')}`
|
||||
)
|
||||
}
|
||||
|
||||
// check sources against request type
|
||||
|
||||
const hasDefault = filenames.includes(DEFAULT_FILENAME)
|
||||
if (
|
||||
(type === RequestType.Html || type === RequestType.Markdown) &&
|
||||
!hasDefault
|
||||
) {
|
||||
throw new Error(
|
||||
`File "${DEFAULT_FILENAME}" is required for ${
|
||||
type === RequestType.Html ? 'HTML' : 'Markdown'
|
||||
} conversion`
|
||||
)
|
||||
}
|
||||
|
||||
if (type === RequestType.Office && hasDefault) {
|
||||
throw new Error(
|
||||
`Default filename "${DEFAULT_FILENAME}" is not allowed for Office convertion, ` +
|
||||
`looks like you didn't set filename for document`
|
||||
)
|
||||
}
|
||||
|
||||
return sources
|
||||
}
|
||||
|
||||
/**
|
||||
* Send actual request to Gotenberg
|
||||
* @return ReadableStream
|
||||
@@ -63,7 +106,7 @@ function please(request: TypedRequest): Promise<NodeJS.ReadableStream | void> {
|
||||
}
|
||||
|
||||
// any other conversion request
|
||||
const sources = toStreams(request.source)
|
||||
const sources = validateSources(request.type, toStreams(request.source))
|
||||
const form = formdata(request.fields, sources)
|
||||
return request.client.post(request.url, form, request.headers)
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
import { createWriteStream, readFileSync } from 'fs'
|
||||
import { convert, gotenberg, office, pipe, please } from '../src'
|
||||
|
||||
// need to run Gotenberg like this
|
||||
// docker run --rm -p 3500:3000 thecodingmachine/gotenberg:6
|
||||
|
||||
const buffer = readFileSync('document.docx')
|
||||
|
||||
pipe(
|
||||
gotenberg('http://localhost:3500'),
|
||||
convert,
|
||||
office,
|
||||
please
|
||||
)(['doc.docx', buffer])
|
||||
.then(pdf => pdf.pipe(createWriteStream(`${__dirname}/document.pdf`)))
|
||||
.catch(console.error)
|
||||
Reference in New Issue
Block a user