1- import { getLogger } from "@ui5/logger" ;
2- const log = getLogger ( "server:middleware:serveResources" ) ;
3- import replaceStream from "replacestream" ;
41import etag from "etag" ;
52import fresh from "fresh" ;
6- import fsInterface from "@ui5/fs/fsInterface" ;
7-
8- const rProperties = / \. p r o p e r t i e s $ / i;
9- const rReplaceVersion = / \. ( l i b r a r y | j s | j s o n ) $ / i;
10- const rManifest = / \/ m a n i f e s t \. j s o n $ / i;
11- const rResourcesPrefix = / ^ \/ r e s o u r c e s \/ / i;
12- const rTestResourcesPrefix = / ^ \/ t e s t - r e s o u r c e s \/ / i;
133
144function isFresh ( req , res ) {
155 return fresh ( req . headers , {
@@ -18,7 +8,7 @@ function isFresh(req, res) {
188}
199
2010/**
21- * Creates and returns the middleware to serve application resources.
11+ * Creates and returns the middleware to serve project resources.
2212 *
2313 * @module @ui 5/server/middleware/serveResources
2414 * @param {object } parameters Parameters
@@ -30,90 +20,23 @@ function createMiddleware({resources, middlewareUtil}) {
3020 return async function serveResources ( req , res , next ) {
3121 try {
3222 const pathname = middlewareUtil . getPathname ( req ) ;
33- let resource = await resources . all . byPath ( pathname ) ;
34- if ( ! resource ) { // Not found
35- if ( ! rManifest . test ( pathname ) || ! rResourcesPrefix . test ( pathname ) ) {
36- next ( ) ;
37- return ;
38- }
39- log . verbose ( `Could not find manifest.json for ${ pathname } . ` +
40- `Checking for .library file to generate manifest.json from.` ) ;
41- const { default : generateLibraryManifest } = await import ( "./helper/generateLibraryManifest.js" ) ;
42- // Attempt to find a .library file, which is required for generating a manifest.json
43- const dotLibraryPath = pathname . replace ( rManifest , "/.library" ) ;
44- const dotLibraryResource = await resources . all . byPath ( dotLibraryPath ) ;
45- if ( dotLibraryResource && dotLibraryResource . getProject ( ) ?. getType ( ) === "library" ) {
46- resource = await generateLibraryManifest ( middlewareUtil , dotLibraryResource ) ;
47- }
48- if ( ! resource ) {
49- // Not a library project, missing .library file or other reason for failed manifest.json generation
50- next ( ) ;
51- return ;
52- }
53- } else if (
54- rManifest . test ( pathname ) && ! rTestResourcesPrefix . test ( pathname ) &&
55- resource . getProject ( ) ?. getNamespace ( )
56- ) {
57- // Special handling for manifest.json file by adding additional content to the served manifest.json
58- // NOTE: This should only be done for manifest.json files that exist in the sources,
59- // not in test-resources.
60- // Files created by generateLibraryManifest (see above) should not be handled in here.
61- // Only manifest.json files in library / application projects should be handled.
62- // resource.getProject.getNamespace() returns null for all other kind of projects.
63- const { default : manifestEnhancer } = await import ( "@ui5/builder/processors/manifestEnhancer" ) ;
64- await manifestEnhancer ( {
65- resources : [ resource ] ,
66- // Ensure that only files within the manifest's project are accessible
67- // Using the "runtime" style to match the style used by the UI5 server
68- fs : fsInterface ( resource . getProject ( ) . getReader ( { style : "runtime" } ) )
69- } ) ;
23+ const resource = await resources . all . byPath ( pathname ) ;
24+ if ( ! resource ) {
25+ // Not found
26+ next ( ) ;
27+ return ;
7028 }
7129
7230 const resourcePath = resource . getPath ( ) ;
73- if ( rProperties . test ( resourcePath ) ) {
74- // Special handling for *.properties files escape non ascii characters.
75- const { default : nonAsciiEscaper } = await import ( "@ui5/builder/processors/nonAsciiEscaper" ) ;
76- const project = resource . getProject ( ) ;
77- let propertiesFileSourceEncoding = project ?. getPropertiesFileSourceEncoding ?. ( ) ;
78-
79- if ( ! propertiesFileSourceEncoding ) {
80- if ( project && project . getSpecVersion ( ) . lte ( "1.1" ) ) {
81- // default encoding to "ISO-8859-1" for old specVersions
82- propertiesFileSourceEncoding = "ISO-8859-1" ;
83- } else {
84- // default encoding to "UTF-8" for all projects starting with specVersion 2.0
85- propertiesFileSourceEncoding = "UTF-8" ;
86- }
87- }
88- const encoding = nonAsciiEscaper . getEncodingFromAlias ( propertiesFileSourceEncoding ) ;
89- await nonAsciiEscaper ( {
90- resources : [ resource ] , options : {
91- encoding
92- }
93- } ) ;
94- }
9531
96- const { contentType, charset } = middlewareUtil . getMimeInfo ( resourcePath ) ;
32+ const { contentType} = middlewareUtil . getMimeInfo ( resourcePath ) ;
9733 if ( ! res . getHeader ( "Content-Type" ) ) {
9834 res . setHeader ( "Content-Type" , contentType ) ;
9935 }
10036
10137 // Enable ETag caching
102- const statInfo = resource . getStatInfo ( ) ;
103- if ( statInfo ?. size !== undefined && ! resource . isModified ( ) ) {
104- let etagHeader = etag ( statInfo ) ;
105- if ( resource . getProject ( ) ) {
106- // Add project version to ETag to invalidate cache when project version changes.
107- // This is necessary to invalidate files with ${version} placeholders.
108- etagHeader = etagHeader . slice ( 0 , - 1 ) + `-${ resource . getProject ( ) . getVersion ( ) } "` ;
109- }
110- res . setHeader ( "ETag" , etagHeader ) ;
111- } else {
112- // Fallback to buffer if stats are not available or insufficient or resource is modified.
113- // Modified resources must use the buffer for cache invalidation so that UI5 CLI changes
114- // invalidate the cache even when the original resource is not modified.
115- res . setHeader ( "ETag" , etag ( await resource . getBuffer ( ) ) ) ;
116- }
38+ const resourceIntegrity = await resource . getIntegrity ( ) ;
39+ res . setHeader ( "ETag" , etag ( resourceIntegrity ) ) ;
11740
11841 if ( isFresh ( req , res ) ) {
11942 // client has a fresh copy of the resource
@@ -122,22 +45,9 @@ function createMiddleware({resources, middlewareUtil}) {
12245 return ;
12346 }
12447
125- let stream = resource . getStream ( ) ;
126-
127- // Only execute version replacement for UTF-8 encoded resources because replaceStream will always output
128- // UTF-8 anyways.
129- // Also, only process .library, *.js and *.json files. Just like it's done in Application-
130- // and LibraryBuilder
131- if ( ( ! charset || charset === "UTF-8" ) && rReplaceVersion . test ( resourcePath ) ) {
132- if ( resource . getProject ( ) ) {
133- stream . setEncoding ( "utf8" ) ;
134- stream = stream . pipe ( replaceStream ( "${version}" , resource . getProject ( ) . getVersion ( ) ) ) ;
135- } else {
136- log . verbose ( `Project missing from resource ${ pathname } "` ) ;
137- }
138- }
139-
140- stream . pipe ( res ) ;
48+ // Pipe resource stream to response
49+ // TODO: Check whether we can optimize this for small or even all resources by using getBuffer()
50+ resource . getStream ( ) . pipe ( res ) ;
14151 } catch ( err ) {
14252 next ( err ) ;
14353 }
0 commit comments