Skip to content

Commit 07146b1

Browse files
Revert "Route requests for missing static files using remote asset metadata - Second attempt" (#1492)
Reverts #1490 I'm going to revert this because people with existing browser storage are going to have issues if /wordpress/wordpress-remote-asset-paths is not found. That was clear when this was originally reverted, but I focused on stopping the deletion of the listing file rather than considering browser storage prior to the existence of the listing. Tomorrow, when returning with a clearer mind, I plan to consider how we might deal with this scenario. cc @WordPress/playground-maintainers
1 parent 7549565 commit 07146b1

File tree

309 files changed

+66604
-92429
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

309 files changed

+66604
-92429
lines changed

packages/php-wasm/node/src/test/php-request-handler.spec.ts

+11-107
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,6 @@ describe.each(SupportedPHPVersions)(
3939
});
4040
});
4141

42-
it('should execute a non-default PHP file in a directory', async () => {
43-
php.mkdirTree('/folder');
44-
php.writeFile(
45-
'/folder/some.php',
46-
`<?php echo 'Some PHP file in a folder.';`
47-
);
48-
const response = await handler.request({
49-
url: '/folder/some.php',
50-
});
51-
expect(response).toEqual({
52-
httpStatusCode: 200,
53-
headers: {
54-
'content-type': ['text/html; charset=UTF-8'],
55-
'x-powered-by': [expect.any(String)],
56-
},
57-
bytes: new TextEncoder().encode('Some PHP file in a folder.'),
58-
errors: '',
59-
exitCode: 0,
60-
});
61-
});
62-
6342
it('should serve a static file', async () => {
6443
php.writeFile('/index.html', `Hello World`);
6544
const response = await handler.request({
@@ -123,8 +102,7 @@ describe.each(SupportedPHPVersions)(
123102
});
124103
});
125104

126-
it('should yield x-file-type=static when a static file is not found and is listed as a remote asset', async () => {
127-
handler.addRemoteAssetPaths(['index.html']);
105+
it('should yield x-file-type=static when a static file is not found', async () => {
128106
const response = await handler.request({
129107
url: '/index.html',
130108
});
@@ -139,19 +117,6 @@ describe.each(SupportedPHPVersions)(
139117
});
140118
});
141119

142-
it('should not yield x-file-type=static when a static file is not found and is not listed as a remote asset', async () => {
143-
const response = await handler.request({
144-
url: '/index.html',
145-
});
146-
expect(response).toEqual({
147-
httpStatusCode: 404,
148-
headers: {},
149-
bytes: expect.any(Uint8Array),
150-
errors: '',
151-
exitCode: 0,
152-
});
153-
});
154-
155120
it('should not yield x-file-type=static when a PHP file is not found', async () => {
156121
const response = await handler.request({
157122
url: '/index.php',
@@ -165,77 +130,6 @@ describe.each(SupportedPHPVersions)(
165130
});
166131
});
167132

168-
it('should redirect to add trailing slash to existing dir', async () => {
169-
php.mkdirTree('/folder');
170-
const response = await handler.request({
171-
url: '/folder',
172-
});
173-
expect(response).toEqual({
174-
httpStatusCode: 301,
175-
headers: {
176-
Location: ['/folder/'],
177-
},
178-
bytes: expect.any(Uint8Array),
179-
errors: '',
180-
exitCode: 0,
181-
});
182-
});
183-
184-
it('should return 200 and pass query strings when a valid request is made to a folder', async () => {
185-
php.mkdirTree('/folder');
186-
php.writeFile('/folder/index.php', `<?php echo $_GET['key'];`);
187-
const response = await handler.request({
188-
url: '/folder/?key=value',
189-
});
190-
expect(response.httpStatusCode).toEqual(200);
191-
expect(response.text).toEqual('value');
192-
});
193-
194-
it('should default a folder request to index.html if it exists and index.php does not', async () => {
195-
php.mkdirTree('/folder');
196-
php.writeFile('/folder/index.html', `INDEX DOT HTML`);
197-
const response = await handler.request({
198-
url: '/folder/?key=value',
199-
});
200-
expect(response.httpStatusCode).toEqual(200);
201-
expect(response.text).toEqual('INDEX DOT HTML');
202-
});
203-
204-
it('should default a folder request to index.php when when both index.php and index.html exist', async () => {
205-
php.mkdirTree('/folder');
206-
php.writeFile('/folder/index.php', `INDEX DOT PHP`);
207-
php.writeFile('/folder/index.html', `INDEX DOT HTML`);
208-
const response = await handler.request({
209-
url: '/folder/?key=value',
210-
});
211-
expect(response.httpStatusCode).toEqual(200);
212-
expect(response.text).toEqual('INDEX DOT PHP');
213-
});
214-
215-
it('should delegate request for non-existent PHP file to /index.php with query args', async () => {
216-
php.writeFile(
217-
'/index.php',
218-
`<?php echo "DEFAULT with key={$_GET['key']}";`
219-
);
220-
const response = await handler.request({
221-
url: '/non/existent/file.php?key=value',
222-
});
223-
expect(response.httpStatusCode).toEqual(200);
224-
expect(response.text).toEqual('DEFAULT with key=value');
225-
});
226-
227-
it('should delegate request for non-existent non-PHP file to /index.php with query args', async () => {
228-
php.writeFile(
229-
'/index.php',
230-
`<?php echo "DEFAULT with key={$_GET['key']}";`
231-
);
232-
const response = await handler.request({
233-
url: '/non/existent/file?key=value',
234-
});
235-
expect(response.httpStatusCode).toEqual(200);
236-
expect(response.text).toEqual('DEFAULT with key=value');
237-
});
238-
239133
it('should return httpStatus 500 if exit code is not 0', async () => {
240134
php.writeFile(
241135
'/index.php',
@@ -407,6 +301,16 @@ describe.each(SupportedPHPVersions)(
407301
expect(response.httpStatusCode).toEqual(200);
408302
expect(response.text).toEqual('value');
409303
});
304+
305+
it('should return 200 and pass query strings when a valid request is made to a folder', async () => {
306+
php.mkdirTree('/folder');
307+
php.writeFile('/folder/index.php', `<?php echo $_GET['key'];`);
308+
const response = await handler.request({
309+
url: '/folder/?key=value',
310+
});
311+
expect(response.httpStatusCode).toEqual(200);
312+
expect(response.text).toEqual('value');
313+
});
410314
}
411315
);
412316

packages/php-wasm/node/src/test/php.spec.ts

-10
Original file line numberDiff line numberDiff line change
@@ -934,16 +934,6 @@ describe.each(SupportedPHPVersions)('PHP %s', (phpVersion) => {
934934
expect(php.isDir(testFilePath)).toEqual(false);
935935
});
936936

937-
it('isFile() should correctly distinguish between a file and a directory', () => {
938-
php.writeFile(testFilePath, 'Hello World!');
939-
expect(php.fileExists(testFilePath)).toEqual(true);
940-
expect(php.isFile(testFilePath)).toEqual(true);
941-
942-
php.mkdir(testDirPath);
943-
expect(php.fileExists(testDirPath)).toEqual(true);
944-
expect(php.isFile(testDirPath)).toEqual(false);
945-
});
946-
947937
it('listFiles() should return a list of files in a directory', () => {
948938
php.mkdir(testDirPath);
949939
php.writeFile(testDirPath + '/test.txt', 'Hello World!');

packages/php-wasm/universal/src/lib/php-request-handler.ts

+47-97
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ export class PHPRequestHandler {
135135
#PATHNAME: string;
136136
#ABSOLUTE_URL: string;
137137
#cookieStore: HttpCookieStore;
138-
#remoteAssetPaths: Set<string>;
139138
rewriteRules: RewriteRule[];
140139
processManager: PHPProcessManager;
141140

@@ -195,8 +194,6 @@ export class PHPRequestHandler {
195194
this.#PATHNAME,
196195
].join('');
197196
this.rewriteRules = rewriteRules;
198-
199-
this.#remoteAssetPaths = new Set<string>();
200197
}
201198

202199
async getPrimaryPhp() {
@@ -309,88 +306,14 @@ export class PHPRequestHandler {
309306
),
310307
this.rewriteRules
311308
);
312-
313-
const primaryPhp = await this.getPrimaryPhp();
314-
315-
let fsPath = joinPaths(this.#DOCROOT, normalizedRequestedPath);
316-
317-
if (primaryPhp.isDir(fsPath)) {
318-
// Ensure directory URIs have a trailing slash. Otherwise,
319-
// relative URIs in index.php or index.html files are relative
320-
// to the next directory up.
321-
//
322-
// Example:
323-
// For a request to "/wp-admin", the relative link "edit.php"
324-
// resolves to "/edit.php" rather than "/wp-admin/edit.php".
325-
//
326-
// This is correct behavior for the browser:
327-
// https://www.rfc-editor.org/rfc/rfc3986#section-5.2.3
328-
//
329-
// But the intent for `/wp-admin/index.php` is that its relative
330-
// URIs are relative to `/wp-admin/`.
331-
//
332-
// In fact, WordPress also redirects like this when given a chance.
333-
// - https://github.com/WordPress/wordpress-develop/blob/b6a3b9c7d1ce33cbeca6f95871a26c48141e524b/src/wp-includes/canonical.php#L696
334-
// - https://github.com/WordPress/wordpress-develop/blob/b6a3b9c7d1ce33cbeca6f95871a26c48141e524b/src/wp-includes/canonical.php#L1036-L1045
335-
// - https://github.com/WordPress/wordpress-develop/blob/b6a3b9c7d1ce33cbeca6f95871a26c48141e524b/src/wp-includes/link-template.php#L3558
336-
if (!fsPath.endsWith('/')) {
337-
return new PHPResponse(
338-
301,
339-
{ Location: [`${requestedUrl.pathname}/`] },
340-
new Uint8Array(0)
341-
);
342-
}
343-
344-
// We can only satisfy requests for directories with a default file
345-
// so let's first resolve to a default path when available.
346-
const defaultFilePath = ['index.php', 'index.html']
347-
.map((defaultFilename) => joinPaths(fsPath, defaultFilename))
348-
.find((possibleDefaultPath) =>
349-
primaryPhp.isFile(possibleDefaultPath)
350-
);
351-
352-
if (defaultFilePath) {
353-
fsPath = defaultFilePath;
354-
}
355-
}
356-
357-
if (fsPath.endsWith('.php')) {
358-
if (primaryPhp.isFile(fsPath)) {
359-
const effectiveRequest: PHPRequest = {
360-
...request,
361-
url: joinPaths(this.#ABSOLUTE_URL, fsPath),
362-
};
363-
return this.#spawnPHPAndDispatchRequest(
364-
effectiveRequest,
365-
requestedUrl
366-
);
367-
}
368-
} else {
369-
if (primaryPhp.isFile(fsPath)) {
370-
return this.#serveStaticFile(primaryPhp, fsPath);
371-
} else if (
372-
// Make sure fsPath doesn't describe any other entity on the filesystem
373-
!primaryPhp.fileExists(fsPath) &&
374-
this.#remoteAssetPaths.has(fsPath)
375-
) {
376-
// This path is listed as a remote asset. Mark it as a static file
377-
// so the service worker knows it can issue a real fetch() to the server.
378-
return new PHPResponse(
379-
404,
380-
{ 'x-file-type': ['static'] },
381-
new TextEncoder().encode('404 File not found')
382-
);
383-
}
309+
const fsPath = joinPaths(this.#DOCROOT, normalizedRequestedPath);
310+
if (!seemsLikeAPHPRequestHandlerPath(fsPath)) {
311+
return this.#serveStaticFile(
312+
await this.processManager.getPrimaryPhp(),
313+
fsPath
314+
);
384315
}
385-
386-
// Delegate unresolved requests to WordPress. This makes WP magic possible,
387-
// like pretty permalinks and dynamically generated sitemaps.
388-
const wpDefaultPath = joinPaths(this.#DOCROOT, 'index.php');
389-
const effectiveRequest: PHPRequest = {
390-
...request,
391-
url: joinPaths(this.#ABSOLUTE_URL, wpDefaultPath),
392-
};
393-
return this.#spawnPHPAndDispatchRequest(effectiveRequest, requestedUrl);
316+
return this.#spawnPHPAndDispatchRequest(request, requestedUrl);
394317
}
395318

396319
/**
@@ -400,6 +323,17 @@ export class PHPRequestHandler {
400323
* @returns The response.
401324
*/
402325
#serveStaticFile(php: PHP, fsPath: string): PHPResponse {
326+
if (!php.fileExists(fsPath)) {
327+
return new PHPResponse(
328+
404,
329+
// Let the service worker know that no static file was found
330+
// and that it's okay to issue a real fetch() to the server.
331+
{
332+
'x-file-type': ['static'],
333+
},
334+
new TextEncoder().encode('404 File not found')
335+
);
336+
}
403337
const arrayBuffer = php.readFileAsBuffer(fsPath);
404338
return new PHPResponse(
405339
200,
@@ -552,19 +486,6 @@ export class PHPRequestHandler {
552486
}
553487
throw new Error(`File not found: ${resolvedFsPath}`);
554488
}
555-
556-
/**
557-
* Add paths to static files we can assume exist remotely.
558-
*
559-
* @param relativePaths A list of paths to remote assets, relative to the document root.
560-
*/
561-
addRemoteAssetPaths(relativePaths: string[]) {
562-
const separator = this.#DOCROOT.endsWith('/') ? '' : '/';
563-
relativePaths.forEach((relativePath) => {
564-
const fsPath = `${this.#DOCROOT}${separator}${relativePath}`;
565-
this.#remoteAssetPaths.add(fsPath);
566-
});
567-
}
568489
}
569490

570491
/**
@@ -582,6 +503,35 @@ function inferMimeType(path: string): string {
582503
return mimeTypes[extension] || mimeTypes['_default'];
583504
}
584505

506+
/**
507+
* Guesses whether the given path looks like a PHP file.
508+
*
509+
* @example
510+
* ```js
511+
* seemsLikeAPHPRequestHandlerPath('/index.php') // true
512+
* seemsLikeAPHPRequestHandlerPath('/index.php') // true
513+
* seemsLikeAPHPRequestHandlerPath('/index.php/foo/bar') // true
514+
* seemsLikeAPHPRequestHandlerPath('/index.html') // false
515+
* seemsLikeAPHPRequestHandlerPath('/index.html/foo/bar') // false
516+
* seemsLikeAPHPRequestHandlerPath('/') // true
517+
* ```
518+
*
519+
* @param path The path to check.
520+
* @returns Whether the path seems like a PHP server path.
521+
*/
522+
export function seemsLikeAPHPRequestHandlerPath(path: string): boolean {
523+
return seemsLikeAPHPFile(path) || seemsLikeADirectoryRoot(path);
524+
}
525+
526+
function seemsLikeAPHPFile(path: string) {
527+
return path.endsWith('.php') || path.includes('.php/');
528+
}
529+
530+
function seemsLikeADirectoryRoot(path: string) {
531+
const lastSegment = path.split('/').pop();
532+
return !lastSegment!.includes('.');
533+
}
534+
585535
/**
586536
* Applies the given rewrite rules to the given path.
587537
*

packages/php-wasm/universal/src/lib/php-worker.ts

-5
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,6 @@ export class PHPWorker implements LimitedPHPApi {
218218
return _private.get(this)!.php!.isDir(path);
219219
}
220220

221-
/** @inheritDoc @php-wasm/universal!/PHP.isFile */
222-
isFile(path: string): boolean {
223-
return _private.get(this)!.php!.isFile(path);
224-
}
225-
226221
/** @inheritDoc @php-wasm/universal!/PHP.fileExists */
227222
fileExists(path: string): boolean {
228223
return _private.get(this)!.php!.fileExists(path);

0 commit comments

Comments
 (0)