mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(upload): detect mime type from file extension (#911)
This commit is contained in:
parent
79b7a8491e
commit
4d84e35096
@ -44,7 +44,6 @@
|
||||
"extract-zip": "^1.6.6",
|
||||
"https-proxy-agent": "^3.0.0",
|
||||
"jpeg-js": "^0.3.6",
|
||||
"mime": "^2.0.3",
|
||||
"pngjs": "^3.4.0",
|
||||
"progress": "^2.0.3",
|
||||
"proxy-from-env": "^1.0.0",
|
||||
@ -56,7 +55,6 @@
|
||||
"@types/debug": "0.0.31",
|
||||
"@types/extract-zip": "^1.6.2",
|
||||
"@types/jpeg-js": "^0.3.7",
|
||||
"@types/mime": "^2.0.0",
|
||||
"@types/node": "^8.10.34",
|
||||
"@types/pngjs": "^3.4.0",
|
||||
"@types/proxy-from-env": "^1.0.0",
|
||||
@ -69,6 +67,7 @@
|
||||
"cross-env": "^5.0.5",
|
||||
"eslint": "^6.6.0",
|
||||
"esprima": "^4.0.0",
|
||||
"formidable": "^1.2.1",
|
||||
"minimist": "^1.2.0",
|
||||
"ncp": "^2.0.0",
|
||||
"node-stream-zip": "^1.8.2",
|
||||
|
||||
@ -432,7 +432,7 @@ export class ElementHandle<T extends Node = Node> extends js.JSHandle<T> {
|
||||
if (typeof item === 'string') {
|
||||
const file: types.FilePayload = {
|
||||
name: platform.basename(item),
|
||||
type: 'application/octet-stream',
|
||||
type: platform.getMimeType(item),
|
||||
data: await platform.readFileAsync(item, 'base64')
|
||||
};
|
||||
return file;
|
||||
@ -620,7 +620,7 @@ export function waitForSelectorTask(selector: string, visibility: types.Visibili
|
||||
export const setFileInputFunction = async (element: HTMLInputElement, payloads: types.FilePayload[]) => {
|
||||
const files = await Promise.all(payloads.map(async (file: types.FilePayload) => {
|
||||
const result = await fetch(`data:${file.type};base64,${file.data}`);
|
||||
return new File([await result.blob()], file.name);
|
||||
return new File([await result.blob()], file.name, {type: file.type});
|
||||
}));
|
||||
const dt = new DataTransfer();
|
||||
for (const file of files)
|
||||
|
||||
207
src/platform.ts
207
src/platform.ts
@ -21,7 +21,6 @@ import * as nodeFS from 'fs';
|
||||
import * as nodePath from 'path';
|
||||
import * as nodeDebug from 'debug';
|
||||
import * as nodeBuffer from 'buffer';
|
||||
import * as mime from 'mime';
|
||||
import * as jpeg from 'jpeg-js';
|
||||
import * as png from 'pngjs';
|
||||
import * as http from 'http';
|
||||
@ -213,9 +212,9 @@ export async function closeFdAsync(fd: number): Promise<void> {
|
||||
return await promisify(nodeFS.close)(fd);
|
||||
}
|
||||
|
||||
export function getMimeType(file: string): string | null {
|
||||
assertFileAccess();
|
||||
return mime.getType(file);
|
||||
export function getMimeType(file: string): string {
|
||||
const extension = file.substring(file.lastIndexOf('.') + 1);
|
||||
return extensionToMime[extension] || 'application/octet-stream';
|
||||
}
|
||||
|
||||
export function urlMatches(urlString: string, match: types.URLMatch | undefined): boolean {
|
||||
@ -358,3 +357,203 @@ export class WebSocketTransport implements ConnectionTransport {
|
||||
this._ws.close();
|
||||
}
|
||||
}
|
||||
|
||||
const extensionToMime: { [key: string]: string } = {
|
||||
'ai': 'application/postscript',
|
||||
'apng': 'image/apng',
|
||||
'appcache': 'text/cache-manifest',
|
||||
'au': 'audio/basic',
|
||||
'bmp': 'image/bmp',
|
||||
'cer': 'application/pkix-cert',
|
||||
'cgm': 'image/cgm',
|
||||
'coffee': 'text/coffeescript',
|
||||
'conf': 'text/plain',
|
||||
'crl': 'application/pkix-crl',
|
||||
'css': 'text/css',
|
||||
'csv': 'text/csv',
|
||||
'def': 'text/plain',
|
||||
'doc': 'application/msword',
|
||||
'dot': 'application/msword',
|
||||
'drle': 'image/dicom-rle',
|
||||
'dtd': 'application/xml-dtd',
|
||||
'ear': 'application/java-archive',
|
||||
'emf': 'image/emf',
|
||||
'eps': 'application/postscript',
|
||||
'exr': 'image/aces',
|
||||
'fits': 'image/fits',
|
||||
'g3': 'image/g3fax',
|
||||
'gbr': 'application/rpki-ghostbusters',
|
||||
'gif': 'image/gif',
|
||||
'glb': 'model/gltf-binary',
|
||||
'gltf': 'model/gltf+json',
|
||||
'gz': 'application/gzip',
|
||||
'h261': 'video/h261',
|
||||
'h263': 'video/h263',
|
||||
'h264': 'video/h264',
|
||||
'heic': 'image/heic',
|
||||
'heics': 'image/heic-sequence',
|
||||
'heif': 'image/heif',
|
||||
'heifs': 'image/heif-sequence',
|
||||
'htm': 'text/html',
|
||||
'html': 'text/html',
|
||||
'ics': 'text/calendar',
|
||||
'ief': 'image/ief',
|
||||
'ifb': 'text/calendar',
|
||||
'iges': 'model/iges',
|
||||
'igs': 'model/iges',
|
||||
'in': 'text/plain',
|
||||
'ini': 'text/plain',
|
||||
'jade': 'text/jade',
|
||||
'jar': 'application/java-archive',
|
||||
'jls': 'image/jls',
|
||||
'jp2': 'image/jp2',
|
||||
'jpe': 'image/jpeg',
|
||||
'jpeg': 'image/jpeg',
|
||||
'jpf': 'image/jpx',
|
||||
'jpg': 'image/jpeg',
|
||||
'jpg2': 'image/jp2',
|
||||
'jpgm': 'video/jpm',
|
||||
'jpgv': 'video/jpeg',
|
||||
'jpm': 'image/jpm',
|
||||
'jpx': 'image/jpx',
|
||||
'js': 'application/javascript',
|
||||
'json': 'application/json',
|
||||
'json5': 'application/json5',
|
||||
'jsx': 'text/jsx',
|
||||
'jxr': 'image/jxr',
|
||||
'kar': 'audio/midi',
|
||||
'ktx': 'image/ktx',
|
||||
'less': 'text/less',
|
||||
'list': 'text/plain',
|
||||
'litcoffee': 'text/coffeescript',
|
||||
'log': 'text/plain',
|
||||
'm1v': 'video/mpeg',
|
||||
'm21': 'application/mp21',
|
||||
'm2a': 'audio/mpeg',
|
||||
'm2v': 'video/mpeg',
|
||||
'm3a': 'audio/mpeg',
|
||||
'm4a': 'audio/mp4',
|
||||
'm4p': 'application/mp4',
|
||||
'man': 'text/troff',
|
||||
'manifest': 'text/cache-manifest',
|
||||
'markdown': 'text/markdown',
|
||||
'mathml': 'application/mathml+xml',
|
||||
'md': 'text/markdown',
|
||||
'mdx': 'text/mdx',
|
||||
'me': 'text/troff',
|
||||
'mesh': 'model/mesh',
|
||||
'mft': 'application/rpki-manifest',
|
||||
'mid': 'audio/midi',
|
||||
'midi': 'audio/midi',
|
||||
'mj2': 'video/mj2',
|
||||
'mjp2': 'video/mj2',
|
||||
'mjs': 'application/javascript',
|
||||
'mml': 'text/mathml',
|
||||
'mov': 'video/quicktime',
|
||||
'mp2': 'audio/mpeg',
|
||||
'mp21': 'application/mp21',
|
||||
'mp2a': 'audio/mpeg',
|
||||
'mp3': 'audio/mpeg',
|
||||
'mp4': 'video/mp4',
|
||||
'mp4a': 'audio/mp4',
|
||||
'mp4s': 'application/mp4',
|
||||
'mp4v': 'video/mp4',
|
||||
'mpe': 'video/mpeg',
|
||||
'mpeg': 'video/mpeg',
|
||||
'mpg': 'video/mpeg',
|
||||
'mpg4': 'video/mp4',
|
||||
'mpga': 'audio/mpeg',
|
||||
'mrc': 'application/marc',
|
||||
'ms': 'text/troff',
|
||||
'msh': 'model/mesh',
|
||||
'n3': 'text/n3',
|
||||
'oga': 'audio/ogg',
|
||||
'ogg': 'audio/ogg',
|
||||
'ogv': 'video/ogg',
|
||||
'ogx': 'application/ogg',
|
||||
'otf': 'font/otf',
|
||||
'p10': 'application/pkcs10',
|
||||
'p7c': 'application/pkcs7-mime',
|
||||
'p7m': 'application/pkcs7-mime',
|
||||
'p7s': 'application/pkcs7-signature',
|
||||
'p8': 'application/pkcs8',
|
||||
'pdf': 'application/pdf',
|
||||
'pki': 'application/pkixcmp',
|
||||
'pkipath': 'application/pkix-pkipath',
|
||||
'png': 'image/png',
|
||||
'ps': 'application/postscript',
|
||||
'pskcxml': 'application/pskc+xml',
|
||||
'qt': 'video/quicktime',
|
||||
'rmi': 'audio/midi',
|
||||
'rng': 'application/xml',
|
||||
'roa': 'application/rpki-roa',
|
||||
'roff': 'text/troff',
|
||||
'rsd': 'application/rsd+xml',
|
||||
'rss': 'application/rss+xml',
|
||||
'rtf': 'application/rtf',
|
||||
'rtx': 'text/richtext',
|
||||
's3m': 'audio/s3m',
|
||||
'sgi': 'image/sgi',
|
||||
'sgm': 'text/sgml',
|
||||
'sgml': 'text/sgml',
|
||||
'shex': 'text/shex',
|
||||
'shtml': 'text/html',
|
||||
'sil': 'audio/silk',
|
||||
'silo': 'model/mesh',
|
||||
'slim': 'text/slim',
|
||||
'slm': 'text/slim',
|
||||
'snd': 'audio/basic',
|
||||
'spx': 'audio/ogg',
|
||||
'stl': 'model/stl',
|
||||
'styl': 'text/stylus',
|
||||
'stylus': 'text/stylus',
|
||||
'svg': 'image/svg+xml',
|
||||
'svgz': 'image/svg+xml',
|
||||
't': 'text/troff',
|
||||
't38': 'image/t38',
|
||||
'text': 'text/plain',
|
||||
'tfx': 'image/tiff-fx',
|
||||
'tif': 'image/tiff',
|
||||
'tiff': 'image/tiff',
|
||||
'tr': 'text/troff',
|
||||
'ts': 'video/mp2t',
|
||||
'tsv': 'text/tab-separated-values',
|
||||
'ttc': 'font/collection',
|
||||
'ttf': 'font/ttf',
|
||||
'ttl': 'text/turtle',
|
||||
'txt': 'text/plain',
|
||||
'uri': 'text/uri-list',
|
||||
'uris': 'text/uri-list',
|
||||
'urls': 'text/uri-list',
|
||||
'vcard': 'text/vcard',
|
||||
'vrml': 'model/vrml',
|
||||
'vtt': 'text/vtt',
|
||||
'war': 'application/java-archive',
|
||||
'wasm': 'application/wasm',
|
||||
'wav': 'audio/wav',
|
||||
'weba': 'audio/webm',
|
||||
'webm': 'video/webm',
|
||||
'webmanifest': 'application/manifest+json',
|
||||
'webp': 'image/webp',
|
||||
'wmf': 'image/wmf',
|
||||
'woff': 'font/woff',
|
||||
'woff2': 'font/woff2',
|
||||
'wrl': 'model/vrml',
|
||||
'x3d': 'model/x3d+xml',
|
||||
'x3db': 'model/x3d+fastinfoset',
|
||||
'x3dbz': 'model/x3d+binary',
|
||||
'x3dv': 'model/x3d-vrml',
|
||||
'x3dvz': 'model/x3d+vrml',
|
||||
'x3dz': 'model/x3d+xml',
|
||||
'xaml': 'application/xaml+xml',
|
||||
'xht': 'application/xhtml+xml',
|
||||
'xhtml': 'application/xhtml+xml',
|
||||
'xm': 'audio/xm',
|
||||
'xml': 'text/xml',
|
||||
'xsd': 'application/xml',
|
||||
'xsl': 'application/xml',
|
||||
'xslt': 'application/xslt+xml',
|
||||
'yaml': 'text/yaml',
|
||||
'yml': 'text/yaml',
|
||||
'zip': 'application/zip'
|
||||
};
|
||||
|
||||
@ -46,7 +46,6 @@ module.exports = {
|
||||
'path': 'dummy',
|
||||
'debug': 'dummy',
|
||||
'buffer': 'dummy',
|
||||
'mime': 'dummy',
|
||||
'jpeg-js': 'dummy',
|
||||
'pngjs': 'dummy',
|
||||
'http': 'dummy',
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
<title>File upload test</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/input/fileupload.html">
|
||||
<input type="file">
|
||||
<input type="submit">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@ -16,6 +16,8 @@
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const formidable = require('formidable');
|
||||
|
||||
const FILE_TO_UPLOAD = path.join(__dirname, '/assets/file-to-upload.txt');
|
||||
|
||||
@ -114,6 +116,41 @@ module.exports.describe = function({testRunner, expect, playwright, FFOX, CHROMI
|
||||
expect(await page.$eval('input', input => input.files.length)).toBe(1);
|
||||
expect(await page.$eval('input', input => input.files[0].name)).toBe('file-to-upload.txt');
|
||||
});
|
||||
it('should detect mime type', async({page, server}) => {
|
||||
let callback;
|
||||
const result = new Promise(f => callback = f);
|
||||
server.setRoute('/upload', async (req, res) => {
|
||||
const form = new formidable.IncomingForm();
|
||||
form.parse(req, function(err, fields, { file1, file2 }) {
|
||||
expect(file1.name).toBe('file-to-upload.txt');
|
||||
expect(file1.type).toBe('text/plain');
|
||||
expect(
|
||||
fs.readFileSync(file1.path).toString()
|
||||
).toBe(
|
||||
fs.readFileSync(path.join(__dirname, '/assets/file-to-upload.txt')).toString()
|
||||
);
|
||||
expect(file2.name).toBe('file-to-upload.png');
|
||||
expect(file2.type).toBe('image/png');
|
||||
expect(
|
||||
fs.readFileSync(file2.path).toString()
|
||||
).toBe(
|
||||
fs.readFileSync(path.join(__dirname, '/assets/file-to-upload.png')).toString()
|
||||
);
|
||||
callback();
|
||||
});
|
||||
});
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent(`
|
||||
<form action="/upload" method="post" enctype="multipart/form-data" >
|
||||
<input type="file" name="file1">
|
||||
<input type="file" name="file2">
|
||||
<input type="submit" value="Submit">
|
||||
</form>`)
|
||||
await (await page.$('input[name=file1]')).setInputFiles(path.join(__dirname, '/assets/file-to-upload.txt'));
|
||||
await (await page.$('input[name=file2]')).setInputFiles(path.join(__dirname, '/assets/file-to-upload.png'));
|
||||
page.click('input[type=submit]');
|
||||
await result;
|
||||
});
|
||||
it('should be able to read selected file', async({page, server}) => {
|
||||
await page.setContent(`<input type=file>`);
|
||||
page.waitForEvent('filechooser').then(({element}) => element.setInputFiles(FILE_TO_UPLOAD));
|
||||
|
||||
@ -29,7 +29,7 @@ require('events').defaultMaxListeners *= parallel;
|
||||
|
||||
let timeout = process.env.CI ? 30 * 1000 : 10 * 1000;
|
||||
if (!isNaN(process.env.TIMEOUT))
|
||||
timeout = parseInt(process.env.TIMEOUT, 10);
|
||||
timeout = parseInt(process.env.TIMEOUT * 1000, 10);
|
||||
const testRunner = new TestRunner({
|
||||
timeout,
|
||||
parallel,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user