Titanium: How to redirect from external to internal URL in webview - ios

So I know how to access both external and internal URL's in the Titanium Webview. But I have no idea how to redirect from an external url to the internal url.
I've got a file called "index.html" in the root folder, so for the webview this should work to access it:
Ti.UI.createWebView({
url: 'index.html'
});
External urls are pretty straight forward
Ti.UI.createWebView({
url: 'http://www.google.com'
});
However, when on the external url, how do I redirect to this local file? None of these work:
LOCAL?
LOCAL?
or the javascript variant
window.location = 'file:///index.html';
Any clues on how to do this?

What I discovered, in the end, are 2 possibilities to achieve this. But it can't be done through redirection.
One: Poll for a certain variable using the webview.evalJS() function
var my_data = $.login_webview.evalJS('global.data;');
Of course, it works only with strings, not with objects. So if you're passing JSON, make sure it is set as a string!
Two: Do an actual redirection server side, to another serverside page and monitor for URL change and then do evalJS() once again, but no need for polling
$.login_webview.addEventListener('load',function(e){
if (e.url.indexOf('mobile/redirect.php') > -1){
var my_data = $.login_webview.evalJS('global.data');
}
});
Just make sure, with 2 that you're actually setting the required data in Javascript using server side technology.

Related

Is there a way to get the URL after a redirect in postman?

I'm working with an API, which after filling out the log in form on their website, redirects back to our website, with a unique code at the end of the URL.
Example URL after redirect:
https://www.mywebsite.com/?code=12431453154545
I have been unable to find a way of viewing this URL in Postman.
Ideally I need to be able to work with that URL to extract the code and store it as a variable.
Any help will be muchly appreciated. I've been trying this all day :( .
When you turn off following redirects in Postman settings, you will be able to inspect 3xx HTTP response which will contain Location header with the URL you want to read.
const url = require("url");
var location = pm.response.headers.get("location");
if (typeof location !== typeof undefined) {
var redirectUrl = url.parse(location, true);
query = redirectUrl.query;
if ("code" in query) {
pm.globals.set("code", query.code);
console.log(pm.globals.get("code"));
}
}
Note that this solution will not work when multiple subsequent redirects happen as you will be inspecting only the first 3xx response. You could solve this by following redirects manually and sending your own requests from Postman script as described in Postman manual.

Workbox redirect the clients page when resource is not cached and offline

Usually whenever I read a blog post about PWA's, the tutorial seems to just precache every single asset. But this seems to go against the app shell pattern a bit, which as I understand is: Cache the bare necessities (only the app shell), and runtime cache as you go. (Please correct me if I understood this incorrectly)
Imagine I have this single page application, it's a simple index.html with a web component: <my-app>. That <my-app> component sets up some routes which looks a little bit like this, I'm using Vaadin router and web components, but I imagine the problem would be the same using React with React Router or something similar.
router.setRoutes([
{
path: '/',
component: 'app-main', // statically loaded
},
{
path: '/posts',
component: 'app-posts',
action: () => { import('./app-posts.js');} // dynamically loaded
},
/* many, many, many more routes */
{
path: '/offline', // redirect here when a resource is not cached and failed to get from network
component: 'app-offline', // also statically loaded
}
]);
My app may have many many routes, and may get very large. I don't want to precache all those resources straight away, but only cache the stuff I absolutely need, so in this case: my index.html, my-app.js, app-main.js, and app-offline.js. I want to cache app-posts.js at runtime, when it's requested.
Setting up runtime caching is simple enough, but my problem arises when my user visits one of the potentially many many routes that is not cached yet (because maybe the user hasn't visited that route before, so the js file may not have loaded/cached yet), and the user has no internet connection.
What I want to happen, in that case (when a route is not cached yet and there is no network), is for the user to be redirected to the /offline route, which is handled by my client side router. I could easily do something like: import('./app-posts.js').catch(() => /* redirect user to /offline */), but I'm wondering if there is a way to achieve this from workbox itself.
So in a nutshell:
When a js file hasn't been cached yet, and the user has no network, and so the request for the file fails: let workbox redirect the page to the /offline route.
Option 1 (not always useful):
As far as I can see and according to this answer, you cannot open a new window or change the URL of the browser from within the service worker. However you can open a new window only if the clients.openWindow() function is called from within the notificationclick event.
Option 2 (hardest):
You could use the WindowClient.navigate method within the activate event of the service worker however is a bit trickier as you still need to check if the file requested exists in the cache or not.
Option 3 (easiest & hackiest):
Otherwise, you could respond with a new Request object to the offline page:
const cacheOnly = new workbox.strategies.CacheOnly();
const networkFirst = new workbox.strategies.NetworkFirst();
workbox.routing.registerRoute(
/\/posts.|\/articles/,
async args => {
const offlineRequest = new Request('/offline.html');
try {
const response = await networkFirst.handle(args);
return response || await cacheOnly.handle({request: offlineRequest});
} catch (error) {
return await cacheOnly.handle({request: offlineRequest})
}
}
);
and then rewrite the URL of the browser in your offline.html file:
<head>
<script>
window.history.replaceState({}, 'You are offline', '/offline');
</script>
</head>
The above logic in Option 3 will respond to the requested URL by using the network first. If the network is not available will fallback to the cache and even if the request is not found in the cache, will fetch the offline.html file instead. Once the offline.html file is parsed, the browser URL will be replaced to /offline.

Redirect after login to backbone route with rails

I am attempting to provide users with a common functionality, redirecting them after login to the originally requested url that is behind a secure path. Example, user clicks link in email triggered via notification in the system, attempts to go to:
https://mysite.com/secure/notifications/1
User is not logged in so kicked back to
https://mysite.com/login
After login they should be brought not to their home page, but to the originally requested url.
I am familar with the technique to store the attempted URL in session before redirecting to login page. The issue is if the URL contains a backbone router after the core URL, ie
https://mysite.com/secure/notifications/1#details
The #details part of the URL is not sent to server it seems, as this is typically for inner page jumping. I am wondering how are web developers dealing with this as JS MVC frameworks like backbone, angular, and other are emerging? Some trick? Any way to actually have the # pass to server in http specification?
Any ideas are appreciated, thank you.
The easiest solution to this problem, if you don't need to support this behaviour for older browsers, is to enable pushState in your backbone router so you don't use # for routes:
Backbone.history.state({pushState: true});
Edit:
The other potential solution, though it is a bit messy, is to do some URL tomfoolery to figure out what should be after the hash and then navigate to that route.
For example, let's say that you want to navigate to:
http://webapp.com/abc/#page1 where 'page1' is the fragment which makes up the Backbone route.
If you instead send the user to http://webapp.com/abc/page1. You can detect whether the browser has pushState. If not, you can replace everything after the 'root' with the hash. Here is some example code which might get you on the right track to supporting both sets of browsers:
var _defaults = {
pushState: Modernizr.history,
silent: true,
root: '/'
};
var start = function(options) {
// Start the routing either with pushstate or without
options = _.extend(_.clone(this._defaults), options);
Backbone.history.start(options);
if (options.pushState) {
Backbone.history.loadUrl(Backbone.history.getFragment());
return;
}
this.degradeToNonHistoryURL();
};
/**
* For fragment URLs, we check if the actual request is for the root i.e '/',
* If it is, we can continue and Backbone will do the magic
* If it isn't we redirect to the root with the route as a fragment
* foo.com/bar/1 -> foo.com/#bar/1
*/
degradeToNonHistoryURL = function() {
var pathName = window.location.pathname;
// If the root is '/', length is one. If the root is 'foo', length is 5 (/foo/)
var rootLength = _getRoot().length;
var isRootRequest = pathName.length === rootLength;
if (!isRootRequest) {
var route = pathName.substr(rootLength);
window.location.href = _getRoot() + '#' + route + window.location.search;
return;
}
Backbone.history.loadUrl(Backbone.history.getFragment());
},
/**
* Get the effective root of the app. Normally it's '/', but if set to 'foo', we want
* to return '/foo/' so we can more easily determine if this is a root request or not.
* #returns {String} The effective root
*/
_getRoot = function() {
if (Backbone.history.options.root === '/') {
return '/';
}
return '/' + Backbone.history.options.root + '/';
},
The trick here is making the pushState URL your canonical URLs and always sending users to those ones. Once browser adoption increases, it should theoretically be easy to cut all of this crap out without having to update all of your links.
After some research it seems there are only two solutions
As recommended by Will, use pushState and only support HTML5 browsers, but this is a massive change for existing apps using hash or hashbang javascript navigation.
Workarounds on server side, the main option here is around providing redirect endpoints to get users where then need to go. Example
/myapp/redirector?pathroot=notifications&hashroot=details&hashparam1=2
this would then build up a url on server side
/myapp/notifications/1#details/2
So in #2 the server cannot receive http requests with hashtags, however it can send them. The browser will receive this full path including hash nav part, and do its normal javascript MVC routing thing.

Broken relative Url in jQuery getJSON Ajax Method

The Url for my development environment is:
http://localhost/mysite/blah...
I am using jQuery & getJSON to perform some ajax actions on my site, which work fine all the time I specify the url as:
/mysite/controller/action
..but this is not ideal as I don't want to hardcode my development url into my seperate jQuery include files.
When the site goes live, it'll be fine to have controller/action or /controller/action as the url as that will resolve ok, but for the development site, it's no go.
I've tried:
controller/action
..but this returns a 404, which suprised me as I thought the lack of / at the front of the url would prevent from looking at the website root.
There must be a neat solution to this?
I would do this by inserting a global constant in my HTML header:
<script type="text/javascript">
var BASE_URL = '/mysite/';
</script>
That would be inserted from your server so it can be dynamically changed.
Later in your script, you'll be able to make AJAX requests with (jQuery style here):
$.ajax( BASE_URL + '/controller/action', ...);
If you're in
/mysite/controller/action
then the correct relative path to
/mysite/some_other_controller/some_other_action
is
../../some_other_controller/some_other/action
You can use this code to get the current path of the .js script and use it for calculate your relative path.
var url;
$("script").each(function () {
if ($(this).attr("src").indexOf("[YOUR_SCRIPT_NAME.JS]") > 0) {
url = $(this).attr("src");
url = url.substr(0, url.lastIndexOf("/"));
return false;
}
});
var final_url = url + "/your_target_script.js"
Replace YOUR_SCRIPT_NAME with the unique name of your script.

Modify URL before loading page in firefox

I want to prefix URLs which match my patterns. When I open a new tab in Firefox and enter a matching URL the page should not be loaded normally, the URL should first be modified and then loading the page should start.
Is it possible to modify an URL through a Mozilla Firefox Addon before the page starts loading?
Browsing the HTTPS Everywhere add-on suggests the following steps:
Register an observer for the "http-on-modify-request" observer topic with nsIObserverService
Proceed if the subject of your observer notification is an instance of nsIHttpChannel and subject.URI.spec (the URL) matches your criteria
Create a new nsIStandardURL
Create a new nsIHttpChannel
Replace the old channel with the new. The code for doing this in HTTPS Everywhere is quite dense and probably much more than you need. I'd suggest starting with chrome/content/IOUtils.js.
Note that you should register a single "http-on-modify-request" observer for your entire application, which means you should put it in an XPCOM component (see HTTPS Everywhere for an example).
The following articles do not solve your problem directly, but they do contain a lot of sample code that you might find helpful:
https://developer.mozilla.org/en/Setting_HTTP_request_headers
https://developer.mozilla.org/en/XUL_School/Intercepting_Page_Loads
Thanks to Iwburk, I have been able to do this.
We can do this my overriding the nsiHttpChannel with a new one, doing this is slightly complicated but luckily the add-on https-everywhere implements this to force a https connection.
https-everywhere's source code is available here
Most of the code needed for this is in the files
IO Util.js
ChannelReplacement.js
We can work with the above files alone provided we have the basic variables like Cc,Ci set up and the function xpcom_generateQI defined.
var httpRequestObserver =
{
observe: function(subject, topic, data) {
if (topic == "http-on-modify-request") {
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
var requestURL = subject.URI.spec;
if(isToBeReplaced(requestURL)) {
var newURL = getURL(requestURL);
ChannelReplacement.runWhenPending(subject, function() {
var cr = new ChannelReplacement(subject, ch);
cr.replace(true,null);
cr.open();
});
}
}
},
get observerService() {
return Components.classes["#mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
},
register: function() {
this.observerService.addObserver(this, "http-on-modify-request", false);
},
unregister: function() {
this.observerService.removeObserver(this, "http-on-modify-request");
}
};
httpRequestObserver.register();
The code will replace the request not redirect.
While I have tested the above code well enough, I am not sure about its implementation. As far I can make out, it copies all the attributes of the requested channel and sets them to the channel to be overridden. After which somehow the output requested by original request is supplied using the new channel.
P.S. I had seen a SO post in which this approach was suggested.
You could listen for the page load event or maybe the DOMContentLoaded event instead. Or you can make an nsIURIContentListener but that's probably more complicated.
Is it possible to modify an URL through a Mozilla Firefox Addon before the page starts loading?
YES it is possible.
Use page-mod of the Addon-SDK by setting contentScriptWhen: "start"
Then after completely preventing the document from getting parsed you can either
fetch a different document from the same domain and inject it in the page.
after some document.URL processing do a location.replace() call
Here is an example of doing 1. https://stackoverflow.com/a/36097573/6085033

Resources