From e726c18788932e2128ece6656064486fc325cc37 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Wed, 25 Aug 2021 11:18:35 -0700 Subject: [PATCH] chore: use 'mime' for various mimeType-extension mappings (#8426) --- src/server/snapshot/snapshotter.ts | 31 +-- src/server/supplements/har/harTracer.ts | 33 +-- .../supplements/recorder/recorderApp.ts | 16 +- src/utils/httpServer.ts | 18 +- utils/testserver/index.js | 203 +----------------- 5 files changed, 11 insertions(+), 290 deletions(-) diff --git a/src/server/snapshot/snapshotter.ts b/src/server/snapshot/snapshotter.ts index c31a545432..b38fdb1738 100644 --- a/src/server/snapshot/snapshotter.ts +++ b/src/server/snapshot/snapshotter.ts @@ -23,6 +23,7 @@ import { frameSnapshotStreamer, SnapshotData } from './snapshotterInjected'; import { calculateSha1, createGuid, monotonicTime } from '../../utils/utils'; import { FrameSnapshot } from './snapshotTypes'; import { ElementHandle } from '../dom'; +import * as mime from 'mime'; export type SnapshotterBlob = { buffer: Buffer, @@ -128,7 +129,7 @@ export class Snapshotter { for (const { url, content, contentType } of data.resourceOverrides) { if (typeof content === 'string') { const buffer = Buffer.from(content); - const sha1 = calculateSha1(buffer) + mimeToExtension(contentType); + const sha1 = calculateSha1(buffer) + '.' + (mime.getExtension(contentType) || 'dat'); this._delegate.onSnapshotterBlob({ sha1, buffer }); snapshot.resourceOverrides.push({ url, sha1 }); } else { @@ -162,31 +163,3 @@ export class Snapshotter { } } } - -const kMimeToExtension: { [key: string]: string } = { - 'application/javascript': 'js', - 'application/json': 'json', - 'application/json5': 'json5', - 'application/pdf': 'pdf', - 'application/xhtml+xml': 'xhtml', - 'application/zip': 'zip', - 'font/otf': 'otf', - 'font/woff': 'woff', - 'font/woff2': 'woff2', - 'image/bmp': 'bmp', - 'image/gif': 'gif', - 'image/jpeg': 'jpeg', - 'image/png': 'png', - 'image/tiff': 'tiff', - 'image/svg+xml': 'svg', - 'text/css': 'css', - 'text/csv': 'csv', - 'text/html': 'html', - 'text/plain': 'text', - 'video/mp4': 'mp4', - 'video/mpeg': 'mpeg', -}; - -function mimeToExtension(contentType: string): string { - return '.' + (kMimeToExtension[contentType] || 'dat'); -} diff --git a/src/server/supplements/har/harTracer.ts b/src/server/supplements/har/harTracer.ts index 3f8524fc36..a5ac5ac419 100644 --- a/src/server/supplements/har/harTracer.ts +++ b/src/server/supplements/har/harTracer.ts @@ -23,6 +23,7 @@ import * as har from './har'; import * as types from '../../types'; import { calculateSha1, monotonicTime } from '../../../utils/utils'; import { eventsHelper, RegisteredListener } from '../../../utils/eventsHelper'; +import * as mime from 'mime'; const FALLBACK_HTTP_VERSION = 'HTTP/1.1'; @@ -223,7 +224,7 @@ export class HarTracer { content.text = buffer.toString('base64'); content.encoding = 'base64'; } else if (this._options.content === 'sha1') { - content._sha1 = calculateSha1(buffer) + mimeToExtension(content.mimeType); + content._sha1 = calculateSha1(buffer) + '.' + (mime.getExtension(content.mimeType) || 'dat'); if (this._started) this._delegate.onContentBlob(content._sha1, buffer); } @@ -231,7 +232,7 @@ export class HarTracer { }).catch(() => {}).then(() => { const postData = response.request().postDataBuffer(); if (postData && harEntry.request.postData && this._options.content === 'sha1') { - harEntry.request.postData._sha1 = calculateSha1(postData) + mimeToExtension(harEntry.request.postData.mimeType); + harEntry.request.postData._sha1 = calculateSha1(postData) + '.' + (mime.getExtension(harEntry.request.postData.mimeType) || 'dat'); if (this._started) this._delegate.onContentBlob(harEntry.request.postData._sha1, postData); } @@ -426,31 +427,3 @@ function calculateRequestBodySize(request: network.Request): number|undefined { return; return new TextEncoder().encode(postData.toString('utf8')).length; } - -const kMimeToExtension: { [key: string]: string } = { - 'application/javascript': 'js', - 'application/json': 'json', - 'application/json5': 'json5', - 'application/pdf': 'pdf', - 'application/xhtml+xml': 'xhtml', - 'application/zip': 'zip', - 'font/otf': 'otf', - 'font/woff': 'woff', - 'font/woff2': 'woff2', - 'image/bmp': 'bmp', - 'image/gif': 'gif', - 'image/jpeg': 'jpeg', - 'image/png': 'png', - 'image/tiff': 'tiff', - 'image/svg+xml': 'svg', - 'text/css': 'css', - 'text/csv': 'csv', - 'text/html': 'html', - 'text/plain': 'text', - 'video/mp4': 'mp4', - 'video/mpeg': 'mpeg', -}; - -function mimeToExtension(contentType: string): string { - return '.' + (kMimeToExtension[contentType] || 'dat'); -} diff --git a/src/server/supplements/recorder/recorderApp.ts b/src/server/supplements/recorder/recorderApp.ts index d6ce54bc47..de62782804 100644 --- a/src/server/supplements/recorder/recorderApp.ts +++ b/src/server/supplements/recorder/recorderApp.ts @@ -23,6 +23,7 @@ import { internalCallMetadata } from '../../instrumentation'; import type { CallLog, EventData, Mode, Source } from './recorderTypes'; import { BrowserContext } from '../../browserContext'; import { isUnderTest } from '../../../utils/utils'; +import * as mime from 'mime'; import { installAppIcon } from '../../chromium/crApp'; declare global { @@ -63,7 +64,7 @@ export class RecorderApp extends EventEmitter { await route.fulfill({ status: 200, headers: [ - { name: 'Content-Type', value: extensionToMime[path.extname(file)] } + { name: 'Content-Type', value: mime.getType(path.extname(file)) || 'application/octet-stream' } ], body: buffer.toString('base64'), isBase64: true @@ -168,16 +169,3 @@ export class RecorderApp extends EventEmitter { await this._page.bringToFront(); } } - -const extensionToMime: { [key: string]: string } = { - '.css': 'text/css', - '.html': 'text/html', - '.jpeg': 'image/jpeg', - '.js': 'application/javascript', - '.png': 'image/png', - '.ttf': 'font/ttf', - '.svg': 'image/svg+xml', - '.webp': 'image/webp', - '.woff': 'font/woff', - '.woff2': 'font/woff2', -}; diff --git a/src/utils/httpServer.ts b/src/utils/httpServer.ts index 7db6e286ba..9edba66bf9 100644 --- a/src/utils/httpServer.ts +++ b/src/utils/httpServer.ts @@ -17,6 +17,7 @@ import * as http from 'http'; import fs from 'fs'; import path from 'path'; +import * as mime from 'mime'; export type ServerRouteHandler = (request: http.IncomingMessage, response: http.ServerResponse) => boolean; @@ -58,7 +59,7 @@ export class HttpServer { try { const content = fs.readFileSync(absoluteFilePath); response.statusCode = 200; - const contentType = extensionToMime[path.extname(absoluteFilePath).substring(1)] || 'application/octet-stream'; + const contentType = mime.getType(path.extname(absoluteFilePath)) || 'application/octet-stream'; response.setHeader('Content-Type', contentType); response.setHeader('Content-Length', content.byteLength); for (const [name, value] of Object.entries(headers || {})) @@ -91,18 +92,3 @@ export class HttpServer { } } } - -const extensionToMime: { [key: string]: string } = { - 'css': 'text/css', - 'html': 'text/html', - 'jpeg': 'image/jpeg', - 'jpg': 'image/jpeg', - 'gif': 'image/gif', - 'js': 'application/javascript', - 'png': 'image/png', - 'ttf': 'font/ttf', - 'svg': 'image/svg+xml', - 'webp': 'image/webp', - 'woff': 'font/woff', - 'woff2': 'font/woff2', -}; diff --git a/utils/testserver/index.js b/utils/testserver/index.js index cab7254499..83d639f30d 100644 --- a/utils/testserver/index.js +++ b/utils/testserver/index.js @@ -21,6 +21,7 @@ const fs = require('fs'); const path = require('path'); const zlib = require('zlib'); const util = require('util'); +const mime = require('mime'); const WebSocketServer = require('ws').Server; const fulfillSymbol = Symbol('fullfil callback'); @@ -289,7 +290,7 @@ class TestServer { return; } const extension = filePath.substring(filePath.lastIndexOf('.') + 1); - const mimeType = extensionToMime[extension] || 'application/octet-stream'; + const mimeType = mime.getType(extension) || 'application/octet-stream'; const isTextEncoding = /^text\/|^application\/(javascript|json)/.test(mimeType); const contentType = isTextEncoding ? `${mimeType}; charset=utf-8` : mimeType; response.setHeader('Content-Type', contentType); @@ -315,204 +316,4 @@ class TestServer { } } -const extensionToMime = { - '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' -}; - module.exports = {TestServer};