Skip to content

Commit

Permalink
Escape characters when generating file name for saving web page resou…
Browse files Browse the repository at this point in the history
…rces

https://bugs.webkit.org/show_bug.cgi?id=267286
rdar://120501555

Reviewed by Ryosuke Niwa and BJ Burg.

In existing implementation, file names generated for saved web page resources could contain '%' or other characters
that need to be encoded for URI. That means, when rewritting subresources URLs in the saved files, we have to encode
file name properly. To avoid this trouble, this patch generates file names that only contains unreserved characters for
URI (RFC 3986), which do not need to be percent-encoded in any case, and compatible with file system.

Updated API test: WebArchive.SaveResourcesValidFileName

* Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp:
(WebCore::isUnreservedURICharacter):
(WebCore::getFileNameFromURIComponent):
(WebCore::generateValidFileName):
* Tools/TestWebKitAPI/Tests/WebKitCocoa/CreateWebArchive.mm:

Canonical link: https://commits.webkit.org/272880@main
  • Loading branch information
szewai committed Jan 11, 2024
1 parent 814028b commit ef11a0f
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 6 deletions.
35 changes: 32 additions & 3 deletions Source/WebCore/loader/archive/cf/LegacyWebArchive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include <wtf/ListHashSet.h>
#include <wtf/RetainPtr.h>
#include <wtf/URLHash.h>
#include <wtf/URLParser.h>
#include <wtf/text/StringBuilder.h>
#include <wtf/text/CString.h>

Expand All @@ -79,16 +80,44 @@ static const CFStringRef LegacyWebArchiveResourceTextEncodingNameKey = CFSTR("We
static const CFStringRef LegacyWebArchiveResourceResponseKey = CFSTR("WebResourceResponse");
static const CFStringRef LegacyWebArchiveResourceResponseVersionKey = CFSTR("WebResourceResponseVersion");

static bool isUnreservedURICharacter(UChar character)
{
return isASCIIAlphanumeric(character) || character == '-' || character == '.' || character == '_' || character == '~';
}

static String getFileNameFromURIComponent(StringView input)
{
auto decodedInput = WTF::URLParser::formURLDecode(input);
if (!decodedInput)
return { };

unsigned length = decodedInput->length();
if (!length)
return { };

StringBuilder result;
result.reserveCapacity(length);
for (unsigned index = 0; index < length; ++index) {
UChar character = decodedInput->characterAt(index);
if (isUnreservedURICharacter(character)) {
result.append(character);
continue;
}
result.append('-');
}

return result.toString();
}

static String generateValidFileName(const URL& url, const HashSet<String>& existingFileNames)
{
auto extractedFileName = url.lastPathComponent().toString();
auto extractedFileName = getFileNameFromURIComponent(url.lastPathComponent());
auto fileName = extractedFileName.isEmpty() ? String::fromLatin1(defaultFileName) : extractedFileName;
fileName = FileSystem::encodeForFileName(fileName);

unsigned count = 0;
do {
if (count)
fileName = makeString(fileName, '(', count, ')');
fileName = makeString(fileName, '-', count);
if (fileName.sizeInBytes() > maxFileNameSizeInBytes)
fileName = fileName.substring(fileName.sizeInBytes() - maxFileNameSizeInBytes, maxFileNameSizeInBytes);
++count;
Expand Down
8 changes: 5 additions & 3 deletions Tools/TestWebKitAPI/Tests/WebKitCocoa/CreateWebArchive.mm
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ function onFramesLoaded() {
NSMutableString *mutableFileName = [NSMutableString stringWithCapacity:256];
for (unsigned i = 0; i < 256; ++i)
[mutableFileName appendString:@"x"];
NSArray *tests = [NSArray arrayWithObjects:[NSString stringWithString:mutableFileName], @"a/image.png", @"b/image.png", @"image.png(1)", @"webarchivetest://host/file:image.png", @"image1/", @"image2///", @"image3.png/./", @"image4/content/../", nil];
NSArray *tests = [NSArray arrayWithObjects:[NSString stringWithString:mutableFileName], @"a/image.png", @"b/image.png", @"image.png(1)", @"webarchivetest://host/file:image.png", @"image1/", @"image2///", @"image3.png/./", @"image4/content/../", @"image5%20file.png", @"image 6.png", nil];
NSMutableString *mutableHTMLString = [NSMutableString string];
NSString *scriptString = [NSString stringWithFormat:@"<script>count = 0; function onImageLoad() { if (++count == %d) window.webkit.messageHandlers.testHandler.postMessage('done'); }</script>", (int)tests.count];
[mutableHTMLString appendString:scriptString];
Expand Down Expand Up @@ -460,13 +460,15 @@ function onFramesLoaded() {
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"webarchivetest://host/main.html"]]];
Util::run(&messageReceived);

NSSet *expectedFileNames = [NSSet setWithArray:[NSArray arrayWithObjects:[mutableFileName substringFromIndex:1], @"image.png", @"image.png(1)", @"image.png(1)(1)", @"file%3Aimage.png", @"image1", @"file", @"image3.png", @"image4", nil]];
NSSet *expectedFileNames = [NSSet setWithArray:[NSArray arrayWithObjects:[mutableFileName substringFromIndex:1], @"image.png", @"image.png-1", @"image.png-1-", @"file-image.png", @"image1", @"file", @"image3.png", @"image4", @"image5-file.png", @"image-6.png", nil]];
static bool saved = false;
[webView _saveResources:directoryURL.get() suggestedFileName:@"host" completionHandler:^(NSError *error) {
EXPECT_NULL(error);
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:[directoryURL URLByAppendingPathComponent:@"host_files"].path error:nil];
NSString *resourceDirectoryName = @"host_files";
NSArray *resourceFileNames = [fileManager contentsOfDirectoryAtPath:[directoryURL URLByAppendingPathComponent:resourceDirectoryName].path error:nil];
NSSet *savedFileNames = [NSSet setWithArray:resourceFileNames];
EXPECT_TRUE([savedFileNames isEqualToSet:expectedFileNames]);

saved = true;
}];
Util::run(&saved);
Expand Down

0 comments on commit ef11a0f

Please sign in to comment.