Skip to content

Commit

Permalink
fix(ios): allow changing WebView read access when loading local file (#…
Browse files Browse the repository at this point in the history
…11431)

Co-authored-by: Lokesh Choudhary <lchoudhary@axway.com>

Fixes TIMOB-27159
  • Loading branch information
vijaysingh-axway authored and sgtcoolguy committed Jan 23, 2020
1 parent eef37a6 commit dd7b319
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 39 deletions.
15 changes: 15 additions & 0 deletions apidoc/Titanium/UI/WebView.yml
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,21 @@ properties:
since: "3.0.0"
default: false

- name: assetsDirectory
summary: Path of file or directory to allow read access by the WebView.
description: |
Use this property to change the resources the web view has access to when loading the content of a local file.
By default the web view only has access to files inside the same directory as the loaded file. To reference
resources from other directories (e.g. a parent directory) change this property accordingly.
If assetsDirectory references a single file, only that file may be loaded. If assetsDirectory references a
directory, files inside that directory may be loaded.
This property needs to be set before [url](Titanium.UI.WebView.url) is assigned to a local file.
type: String
platforms: [iphone, ipad]
since: "9.0.0"

- name: html
summary: HTML content of this web view.
description: |
Expand Down
1 change: 1 addition & 0 deletions iphone/Classes/TiUIWebView.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
BOOL _tiCookieHandlerAdded;
BOOL ignoreNextRequest;
SEL reloadMethod;
NSString *assetsDirectory;
}

@property (nonatomic, retain) id reloadData;
Expand Down
51 changes: 12 additions & 39 deletions iphone/Classes/TiUIWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ - (void)setBackgroundColor_:(id)value
[[self webView] setBackgroundColor:[[TiUtils colorValue:value] color]];
}

- (void)setAssetsDirectory_:(id)value
{
ENSURE_TYPE_OR_NIL(value, NSString);
assetsDirectory = value;
}

- (void)setData_:(id)value
{
ignoreNextRequest = YES;
Expand Down Expand Up @@ -697,59 +703,26 @@ - (void)addCookieHeaderForRequest:(NSMutableURLRequest *)request

- (void)loadLocalURL:(NSURL *)url
{
NSStringEncoding encoding = NSUTF8StringEncoding;
NSString *path = [url path];
NSString *mimeType = [Mimetypes mimeTypeForExtension:path];
NSError *error = nil;
NSURL *baseURL = [[url copy] autorelease];

// first check to see if we're attempting to load a file from the
// filesystem and if so, and it exists, use that
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
// per the Apple docs on what to do when you don't know the encoding ahead of a
// file read:
// step 1: read and attempt to have system determine
NSString *html = [NSString stringWithContentsOfFile:path usedEncoding:&encoding error:&error];
if (html == nil && error != nil) {
//step 2: if unknown encoding, try UTF-8
error = nil;
html = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
if (html == nil && error != nil) {
//step 3: try an appropriate legacy encoding (if one) -- what's that? Latin-1?
//at this point we're just going to fail
//This is assuming, of course, that this just isn't a pdf or some other non-HTML file.
if ([[path pathExtension] hasPrefix:@"htm"]) {
DebugLog(@"[ERROR] Couldn't determine the proper encoding. Make sure this file: %@ is UTF-8 encoded.", [path lastPathComponent]);
}
} else {
// if we get here, it succeeded using UTF8
encoding = NSUTF8StringEncoding;
}
} else {
error = nil;
}
if ((error != nil && [error code] == 261) || [mimeType isEqualToString:(NSString *)svgMimeType]) {
//TODO: Shouldn't we be checking for an HTML mime type before trying to read? This is right now rather inefficient, but it
//Gets the job done, with minimal reliance on extensions.
// this is a different encoding than specified, just send it to the webview to load

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[self loadRequestWithURL:url];
return;
} else if (error != nil) {
DebugLog(@"[DEBUG] Cannot load file: %@. Error message was: %@", path, error);
return;
}
NSURL *requestURL = [NSURL fileURLWithPath:path];
[self loadRequestWithURL:requestURL];
NSString *readAccessDirectory = assetsDirectory ?: [[url URLByDeletingLastPathComponent] absoluteString];

[[self webView] loadFileURL:requestURL
allowingReadAccessToURL:[NSURL URLWithString:readAccessDirectory]];

} else {
// convert it into a app:// relative path to load the resource
// from our application
url = [[self fileURLToAppURL:url] retain];
NSData *data = [TiUtils loadAppResource:url];
NSString *html = nil;
if (data != nil) {
html = [[[NSString alloc] initWithData:data encoding:encoding] autorelease];
html = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
}
if (html != nil) {
//Because local HTML may rely on JS that's stored in the app: schema, we must kee the url in the app: format.
Expand Down
12 changes: 12 additions & 0 deletions iphone/Classes/TiUIWebViewProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@

@implementation TiUIWebViewProxy

static NSArray *webViewKeySequence;

#pragma mark Internal

- (NSArray *)keySequence
{
if (webViewKeySequence == nil) {
webViewKeySequence = [[NSArray arrayWithObjects:@"assetsDirectory", @"url", nil] retain];
}
return webViewKeySequence;
}

- (id)_initWithPageContext:(id<TiEvaluator>)context
{
if (self = [super _initWithPageContext:context]) {
Expand Down
17 changes: 17 additions & 0 deletions tests/Resources/html/example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>

<head>
<title>
Title
</title>
<script type="text/javascript">
window.onload = function() {
window.location.href="../folder with spaces/comingSoon.html"
};
</script>
</head>

<h1> Test HTML </h1>

</html>
85 changes: 85 additions & 0 deletions tests/Resources/ti.ui.webview.addontest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Appcelerator Titanium Mobile
* Copyright (c) 2011-Present by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
/* eslint-env mocha */
/* eslint no-unused-expressions: "off" */
'use strict';
var should = require('./utilities/assertions'),
utilities = require('./utilities/utilities');

describe('Titanium.UI.WebView', function () {
var win;
this.slow(3000);
this.timeout(30000);

afterEach(function (done) {
if (win) {
// If `win` is already closed, we're done.
let t = setTimeout(function () {
if (win) {
win = null;
done();
}
}, 3000);

win.addEventListener('close', function listener () {
clearTimeout(t);

if (win) {
win.removeEventListener('close', listener);
}
win = null;
done();
});
win.close();
} else {
win = null;
done();
}
});

it.ios('#assetsDirectory', function (finish) {
win = Ti.UI.createWindow();
var loadCount = 0;
function createDirectory(f) {
if (f && !f.exists()) {
f.createDirectory();
}
return f;
}

// Copy from Resources to cache folder
var cacheDir = createDirectory(Ti.Filesystem.getFile(Ti.Filesystem.applicationCacheDirectory));
createDirectory(Ti.Filesystem.getFile(cacheDir.nativePath, 'html'));
createDirectory(Ti.Filesystem.getFile(cacheDir.nativePath, 'folder with spaces'));

var htmlFile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, 'html', 'example.html');
var nextHtmlFile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, 'folder with spaces', 'comingSoon.html');

var htmlInCache = Ti.Filesystem.getFile(cacheDir.nativePath, 'html', 'example.html');
var nextHtmlInCache = Ti.Filesystem.getFile(cacheDir.nativePath, 'folder with spaces', 'comingSoon.html');

htmlFile.copy(htmlInCache.nativePath);
nextHtmlFile.copy(nextHtmlInCache.nativePath);

var webView = Ti.UI.createWebView({
width: Ti.UI.FILL,
height: Ti.UI.FILL,
url: htmlInCache.nativePath,
assetsDirectory: cacheDir.nativePath
});

webView.addEventListener('load', function () {
loadCount++;
if (loadCount > 1) {
finish();
}
});
win.add(webView);
win.open();
});

});

0 comments on commit dd7b319

Please sign in to comment.