Safari losing hash params on http redirection - safari

I am facing an issue wherein the url fragments are not getting
preserved on redirect in Safari as they should be according to the
http specifications.
Setting -
`/url1` redirects to `/url2#hash`
`/url2` redirects to `/url3`
Expected behaviour -
Hitting `/url1` should redirect to `/url3#hash`
Observed behaviour -
Chrome/FF - Hitting `/url1` redirects to `/url3#hash`
Safari(11+) - Hitting `/url1` redirects to `/url3`
I did read the issue reported for earlier versions of Safari. I also tried the solutions posted in other SO threads in vain.
Any help is appreciated.

We ran into the same issue today and made some additional observations. We were also able to reproduce the problem with an example Spring Boot app:
#Controller
class RedirectController {
#GetMapping("/url1")
String url1() {
return "redirect:/url2#hash";
}
#GetMapping("/url2")
String url2() {
return "redirect:/url3";
}
#GetMapping("/url3")
#ResponseBody
String url3() {
return "Hello World";
}
}
When running with Safari 14.1.2 on OSX 10.15.7 (Catalina) hitting /url1/ leads to /url3 without carrying over the fragment (#hash) from /url2.
But doing so with Safari 14.1.2 (same version) on OSX 11.5.2 (Big Sur) works. Hitting /url1 leads to /url3#hash.
In any case hitting /url1#this-is-fragment leads to /url3#this-is-fragment.
Our hypothesis is, that Safari (on Catalina) carries over fragments only if they are created in the browser and not on the server. Safari on Big Sur seems to behave like other browsers (e.g. Firefox and Chrome).
Based on that hypothesis one "solution" is a client side redirect, for example via meta refresh:
#Controller
class RedirectController {
#GetMapping("/url1")
#ResponseBody
String url1ClientSideRedirect() {
return """
<html>
<head>
<meta http-equiv="refresh" content="0;URL='/url2#hash'">
</head>
<body></body>
</html>
""";
}
#GetMapping("/url2")
String url2() {
return "redirect:/url3";
}
#GetMapping("/url3")
#ResponseBody
String url3() {
return "Hello World";
}
}
I suppose any client side JavaScript working with window.location would work as well.

Related

URL Rewrite exceptions for Blazor WebAssembly Hosted deployment

During development, i have used Swagger on the server side of my Blazor WebAssembly App. Always launching (debug) using kestrel instead of IIS Express.
Routing worked as expected, all my component routed properly and if i manually typed /swagger, i got to the swagger page. All good.
We have deployed under IIS on our pre-prod servers, the Server side and Blazor WebAssembly App (client) work as expected and are usable, however, my /swagger url gets rewritten (I assume) to go somewhere in my App instead of letting it go to Swagger, obviously there isn't any component that answers to /swagger.
My only guess is that, when hosted on IIS, the aspnet core app takes care of telling IIS what to rewrite and how (similar to the configs that could be provided thru a web.config for a "Standalone" deployment.)
I can't find how to specify exceptions, I've been following the doc at
https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/blazor/webassembly?view=aspnetcore-3.1#iis
Any idea how i could add an exception for /swagger ?
EDIT:
Turns out it works without issues in Chrome, only Firefox has the unwanted behavior. If i clear my cache, or use Incognito mode, the issue does not happen in Firefox. So, it seems that Firefox caches some stuff and tries to send my URL input to the Blazor Wasm instead of going thru to the server. I will debug some more with the dev tools and fiddler open to try and figure it out, will report back.
Turns out there this is part of the service-worker.js file that is published. It is different in dev than what gets published (which makes sense).
During my debugging i was able to reproduce the issue on all browsers (Edge, Chrome and Firefox), regardless of being in Incognito/Private mode or not.
Once the service-worker is running, it handles serving requests from cache/index.html of the Blazor WebAssembly app.
If you go into your Blazor WebAssembly Client "wwwroot" folder, you'll find a service-worker.js and a service-worker.published.js. In the service-worker.published.js, you will find a function that looks like this :
async function onFetch(event) {
let cachedResponse = null;
if (event.request.method === 'GET') {
// For all navigation requests, try to serve index.html from cache
// If you need some URLs to be server-rendered, edit the following check to exclude those URLs
const shouldServeIndexHtml = event.request.mode === 'navigate'
&& !event.request.url.includes('/connect/')
&& !event.request.url.includes('/Identity/');
const request = shouldServeIndexHtml ? 'index.html' : event.request;
const cache = await caches.open(cacheName);
cachedResponse = await cache.match(request);
}
return cachedResponse || fetch(event.request);
}
Simply following the instructions found in the code comments is gonna fix the issue. So we ended up adding an exclusion for "/swagger" like so :
&& !event.request.url.includes('/swagger')
Hopefully this post is useful for people who are gonna want to serve things outside of the service worker, not only Swagger.
Do you have UseSwagger first in your Startup.Configure method?
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSwagger();
app.UseSwaggerUI(c =>
c.SwaggerEndpoint("/swagger/v1/swagger.json", "YourAppName V1")
);
In Startup.ConfigureServices I have the Swagger code last.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSwaggerGen(c =>
c.SwaggerDoc(
name: "v1",
info: new OpenApiInfo
{
Title = "YourAppName",
Version = "V1",
}));
}
This is working just fine for us.
Note: You must navigate to https://yourdomain/swagger/index.html

signalR : /signalr/hubs is not generated

I can get this tutorial to work in a new project, but not in my existing project.
My project is an ASP.Net MVC 4 web application with the following attribute in the web.config file:
<appSettings>
<add key="webpages:Enabled" value="true"/>
</appSettings>
This is because my application is a Single-Page-Application, which uses AngularJS on the client side. The only page in my application is index.cshtml, to which I've added the relevant code for signalR:
<!-- signalR chat -->
<script src="~/Scripts/jquery.signalR-1.0.0.js"></script>
<!--Reference the autogenerated SignalR hub script. -->
<script src="/signalr/hubs"></script>
<!--Add script to update the page and send messages.-->
<script type="text/javascript">
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (name, message) {
// Html encode display name and message.
var encodedName = $('<div />').text(name).html();
var encodedMsg = $('<div />').text(message).html();
// Add the message to the page.
$('#discussion').append('<li><strong>' + encodedName
+ '</strong>: ' + encodedMsg + '</li>');
};
// Get the user name and store it to prepend to messages.
$('#displayname').val(prompt('Enter your name:', ''));
// Set initial focus to message input box.
$('#message').focus();
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
});
</script>
Then I've got the ChatHub.cs file:
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
}
}
And finally in the global.asax:
protected void Application_Start()
{
RouteTable.Routes.MapHubs();
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
When I run the application, the /signalr/hubs file is not generated. I get a 404 when requesting the file, and it crashes on the line:
chat.client.broadcastMessage = function (name, message) { ....
because chat is null as the previous line did not find chatHub:
var chat = $.connection.chatHub;
Does anyone know what's wrong with my code ?
UPDATE
I have solved my problem by changing the line::
<script src="/signalr/hubs"></script>
to
<script src="~/signalr/hubs"></script>
I have solved my problem by changing the line::
<script src="/signalr/hubs"></script>
to
<script src="~/signalr/hubs"></script>
Also, the reason why /signalr/hubs are not generated is forget to Map SignalR in OWIN Startup Configuration.
public class Startup
{
public void Configuration(IAppBuilder appBuilder){
...
appBuilder.MapSignalR();
...
}
...
In my case, it was because my ChatHub class was not marked public.
I had a similar problem where the hubs file wasn't being generated. It looks like the OP was following the steps here. The way I fixed the problem had to do with the jquery includes. The tutorial I linked below was written with jquery 1.6.4 and jquery-signalr version 2.1.0. When Visual Studio generated the Scripts folder for me, it used jquery version 1.10.2 and jquery-signalr version 2.0.2.
The way I fixed this was simply to edit the index.html file. Note that you can use Chrome's javascript console window Ctrl+Shift+J to see errors.
For me the solution was to reinstall all the packages and restore all the dependecies.
Open nuget powershell console and use this command.
Update-Package -Reinstall
I'll like to add that the signalR Readme file have some note about this issue.
And also if your signalR page is in a PartialView some script should be place in the master page.
Please see http://go.microsoft.com/fwlink/?LinkId=272764 for more information on using SignalR.
Upgrading from 1.x to 2.0
-------------------------
Please see http://go.microsoft.com/fwlink/?LinkId=320578 for more information on how to
upgrade your SignalR 1.x application to 2.0.
Mapping the Hubs connection
----------------------------
To enable SignalR in your application, create a class called Startup with the following:
using Microsoft.Owin;
using Owin;
using MyWebApplication;
namespace MyWebApplication
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.MapSignalR();
}
}
}
Getting Started
---------------
See http://www.asp.net/signalr/overview/getting-started for more information on how to get started.
Why does ~/signalr/hubs return 404 or Why do I get a JavaScript error: 'myhub is undefined'?
--------------------------------------------------------------------------------------------
This issue is generally due to a missing or invalid script reference to the auto-generated Hub JavaScript proxy at '~/signalr/hubs'.
Please make sure that the Hub route is registered before any other routes in your application.
In ASP.NET MVC 4 you can do the following:
<script src="~/signalr/hubs"></script>
If you're writing an ASP.NET MVC 3 application, make sure that you are using Url.Content for your script references:
<script src="#Url.Content("~/signalr/hubs")"></script>
If you're writing a regular ASP.NET application use ResolveClientUrl for your script references or register them via the ScriptManager
using a app root relative path (starting with a '~/'):
<script src='<%: ResolveClientUrl("~/signalr/hubs") %>'></script>
If the above still doesn't work, you may have an issue with routing and extensionless URLs. To fix this, ensure you have the latest
patches installed for IIS and ASP.NET.
In my case i was missing :
app.MapSignalR();
in public void Configuration(IAppBuilder app) function located in startup.cs
Some advice for those that start scaling out from the get go. In my case I was working on getting a remote client to work and never realized that
A. the tutorial example lists the web app(server) startup in a using statement, after which the web app disposes properly and no long exists.
I got rid of the using statement and keep a reference to the web app
for later disposal
B. the client has a different url than the server. the example relies on them having the same url. the "/signalr/hubs" is an endpoint run by the signalr server, called by the signalr client to get a script of all the hubs the server implements.
You need to include "http://myServerURL/signalr/hubs", rather than making it
relative to the client.
No lies. This tripped me up for a solid 2 weeks, because by some magic the solution worked anyways on my coworker's setup. This caused me to keep looking for IIS settings and firewall settings and CORS settings that must have been blocking the connection on my computer. I scavenged every last stack overflow question I could and the ultimate answer was that I should have just implemented a heartbeat monitor on the web app from the start.
Good luck and hopefully this saves other people some time.
See if Microsoft.Owin.Host.Systemweb nuget package is not installed, and therefore not building the dynamic js lib.
OwinStartup not firing

Apache + Symfony2 + HTTPS + Node.js + Socket.io: socket.emit not firing

I've been spending hours upon hours on this problem, but to no avail.
EDIT: solution found (see my answer)
Project background
I'm building a project in Symfony2, which requires a module for uploading large files. I've opted for Node.js and Socket.IO (I had to learn it from scratch, so I might be missing something basic).
I'm combining these with the HTML5 File and FileReader API's to send the file in slices from the client to the server.
Preliminary tests showed this approach working great as a standalone app, where everything was handled and served by Node.js, but integration with Apache and Symfony2 seems problematic.
The application has an unsecured and secured section. My goal is to use Apache on ports 80 and 443 for serving the bulk of the app built in Symfony2, and Node.js with Socket.io on port 8080 for file uploads. The client-side page connecting to the socket will be served by Apache, but the socket will run via Node.js. The upload module has to run over HTTPS, as the page resides in a secured environment with an authenticated user.
The problem is events using socket.emit or socket.send don't seem to work. Client to server, or server to client, it makes no difference. Nothing happens and there are no errors.
The code
The code shown is a simplified version of my code, without the clutter and sensitive data.
Server
var httpsModule = require('https'),
fs = require('fs'),
io = require('socket.io');
var httpsOptions =
{
key: fs.readFileSync('path/to/key'),
cert: fs.readFileSync('/path/to/cert'),
passphrase: "1234lol"
}
var httpsServer = httpsModule.createServer(httpsOptions);
var ioServer = io.listen(httpsServer);
httpsServer.listen(8080);
ioServer.sockets.on('connection', function(socket)
{
// This event gets bound, but never fires
socket.on('NewFile', function(data)
{
// To make sure something is happening
console.log(data);
// Process the new file...
});
// Oddly, this one does fire
socket.on('disconnect', function()
{
console.log("Disconnected");
});
});
Client
// This is a Twig template, so I'll give an excerpt
{% block javascripts %}
{{ parent() }}
<script type="text/javascript" src="https://my.server:8080/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect("my.server:8080",
{
secure: true,
port: 8080
});
// Imagine this is the function initiating the file upload
// File is an object containing metadata about the file like, filename, size, etc.
function uploadNewFile(file)
{
socket.emit("NewFile", item);
}
</script>
{% endblock %}
So the problem is...
Of course there's much more to the application than this, but this is where I'm stuck. The page loads perfectly without errors, but the emit events never fire or reach the server (except for the disconnect event). I've tried with the message event on both client and server to check if it was a problem with only custom events, but that didn't work either. I'm guessing something is blocking client-server communication (it isn't the firewall, I've checked).
I'm completely at a loss here, so please help.
EDIT: solution found (see my answer)
After some painstaking debugging, I've found what was wrong with my setup. Might as well share my findings, although they are (I think) unrelated to Node.js, Socket.IO or Apache.
As I mentioned, my question had simplified code to show you my setup without clutter. I was, however, setting up the client through an object, using the properties to configure the socket connection. Like so:
var MyProject = {};
MyProject.Uploader =
{
location: 'my.server:8080',
socket: io.connect(location,
{
secure: true,
port: 8080,
query: "token=blabla"
}),
// ...lots of extra properties and methods
}
The problem lay in the use of location as a property name. It is a reserved word in Javascript and makes for some strange behaviour in this case. I found it strange that an object's property name can't be a reserved word, so I decided to test. I had also noticed I was referencing the property incorrectly, I forgot to use this.location when connection to the socket. So I changed it to this, just as a test.
var MyProject = {};
MyProject.Uploader =
{
location: 'my.server:8080',
socket: io.connect(this.location,
{
secure: true,
port: 8080,
query: "token=blabla"
}),
// ...lots of extra properties and methods
}
But to no avail. I was still not getting data over the socket. So the next step seemed logical in my frustration-driven debugging rage. Changing up the property name fixed everything!
var MyProject = {};
MyProject.Uploader =
{
socketLocation: 'my.server:8080',
socket: io.connect(this.socketLocation,
{
secure: true,
port: 8080,
query: "token=blabla"
}),
// ...lots of extra properties and methods
}
This approach worked perfectly, I was getting loads of debug messages. SUCCESS!!
Whether it is expected behaviour in Javascript to override (or whatever is happening here, "to misuse" feels like a better way of putting it to me right now) object properties if you happen to use a reserved word, I don't know. I only know I'm steering clear of them from now on!
Hope it helps anyone out there!

RavenDB in embedded mode - Raven Silverlight Studio (Raven.Studio.xap) not working

I have a small console application doing some persistence with Raven which is working fine, but I just can't get the Raven Studio Web-App working.
I think I have read every article/blog post on the web which is around, but I haven't got it working.
The project is referencing the Raven.Client.Embedded, Raven.Client.Lightweight and Raven.Storage.Esent assemblies)
Here is the really simple code starting up my console app:
class Program
{
static void Main(string[] args)
{
EmbeddableDocumentStore store = new EmbeddableDocumentStore { DataDirectory = #"C:\temp\ravendata", UseEmbeddedHttpServer = true };
store.Initialize();
Console.WriteLine("Initialized");
while (true)
{
string line = Console.ReadLine();
if (line == "w")
{
Changeset cs = CreateChangeset();
using (var session = store.OpenSession())
{
session.Store(cs);
session.SaveChanges();
}
Console.WriteLine("Written.");
}
}
The question is: Where to put the Raven.Studio.xap in order to get it running in the browser (http://localhost:8080/Raven/studio.html)?
It's not working in the bin/debug output folder of my console app (which would be the most logical area where it should be), as well as it isn't if I put it in the root of my console application.
Sorry to ask this thing again, but it seems there is some point I am missing on this to get it up and running. ;)
Thanks for your help, R's, Rene
You are right, I've tried it using a new console application project and had the same issues, altough I copied the file Raven.Studio.xap into the \bin\debug AFTER I had seen the error message for the first time.
I found out, that the reason for this has to do with browser-caching. Even though the file would be available now, the embedded http-server returns 304 Not Modified, because it had sent the If-None-Match header into the request. Therefore, the cached "not-found" page in the browser cache will be used.
I fixed it and sent a patch to Ayende. However the solution now is:
1) make sure Raven.Studio.xap is under \bin\debug
2) clear the browsers cache

Why are cookies unrecognized when a link is clicked from an external source (i.e. Excel, Word, etc...)

I noticed that when a link is clicked externally from the web browser, such as from Excel or Word, that my session cookie is initially unrecognized, even if the link opens up in a new tab of the same browser window.
The browser ends up recognizing its cookie eventually, but I am puzzled as to why that initial link from Excel or Word doesn't work. To make it even more challenging, clicking a link works fine from Outlook.
Does anybody know why this might be happening? I'm using the Zend Framework with PHP 5.3.
This is because MS Office is using Hlink.dll component to lookup if the link is Office document or something else. MS Office expect to open the document linked within documents without the aid of external browser (using Hlink.dll component of IE6).
If session cookie protects website Hlink naturally is being redirected to login page and having reached HTML page and not able to "understand" it opens it in external browser. Note that it opens not original URL (expected behavior) but the result of redirect, even if it was 302 redirect.
Microsoft has that bug in unsupported component (Hlink.dll), instead of recognizing the bug they turn it over to our head (trying to convince us that it is flaw of SSO system we use, i.e. session cookies) and refuses to upgrade it. It offers workaround that turns off the lookup functionality of MS Office:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Office\9.0\Common\Internet\ForceShellExecute:DWORD=1
Or offer us to workaround serverside, to avoid HTTP redirects and change into Javascript redirects or META REFRESH redirects (i.e. to have Hlink get text/html page on original URL and make it run external browser to handle it).
Server side this worked for me in IIS (using a rewrite rule)
<rule name="WordBypass" enabled="true" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_USER_AGENT}" pattern="Word|Excel|PowerPoint|ms-office" />
</conditions>
<action type="CustomResponse" statusCode="200" statusReason="Refresh" statusDescription="Refresh" />
</rule>
We had this same problem and wrote an open source gem to help those using rails: https://github.com/spilliton/fix_microsoft_links
You can use the same approach we used on any framework though:
Detect if the user agent is from a Microsoft product
Render a blank html page with a meta refresh tag that will cause the browser to refresh the page with the correct cookies
Example code here: https://github.com/spilliton/fix_microsoft_links/blob/master/lib/fix_microsoft_links.rb
PHP solution:
This prevents the MS product recognising the redirect. MS therefore launches a browser from the required link.
if (isset($_SERVER['HTTP_USER_AGENT']))
{
$http_user_agent = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/Word|Excel|PowerPoint|ms-office/i', $http_user_agent))
{
// Prevent MS office products detecting the upcoming re-direct .. forces them to launch the browser to this link
die();
}
}
.. redirect after this code
Fix for VB.NET:
Dim userAgent As String = System.Web.HttpContext.Current.Request.UserAgent
If userAgent.Contains("Word") Or userAgent.Contains("Excel") Or userAgent.Contains("PowerPoint") Or userAgent.Contains("ms-office") Then
System.Web.HttpContext.Current.Response.Clear()
System.Web.HttpContext.Current.Response.Write("<html><head><meta http-equiv='refresh' content='0'/></head><body></body></html>")
System.Web.HttpContext.Current.Response.End()
End If
It basically forces the browser to refresh the page, so the request comes in with the user agent of the browser and all the correct cookies.
Here is a solution for C# ASP.NET based on spilliton's answer above. In Global.asax.cs, add the following:
private static string MSUserAgentsRegex = #"[^\w](Word|Excel|PowerPoint|ms-office)([^\w]|\z)";
protected void Application_OnPostAuthenticateRequest(object sender, EventArgs e)
{
if (System.Text.RegularExpressions.Regex.IsMatch(Request.UserAgent, MSUserAgentsRegex))
{
Response.Write("<html><head><meta http-equiv='refresh' content='0'/></head><body></body></html>");
Response.End();
}
}
Here is an example of the fix using a dotnet core middleware:
public class MicrosoftOfficeLinksHandlingMiddleware
{
private static readonly Regex MsUserAgentsRegex = new Regex(#"[^\w](Word|Excel|PowerPoint|ms-office)([^\w]|\z)");
private readonly RequestDelegate _next;
public MicrosoftOfficeLinksHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
string userAgent = context.Request.Headers["User-Agent"].FirstOrDefault();
if (userAgent != null && MsUserAgentsRegex.IsMatch(userAgent))
{
// just return an empty response to the office agent
return;
}
await _next(context);
}
}
1.From excel/word point to http://example.com/from_excel.php
2.In "from_excel.php" redirect to page where you use session
<script>document.location.href = "http://example.com/page_with_session.php"; </script>
Here is how to workaround this with Java and Spring via a Filter:
/**
* To see why this is necessary, check out this page:
* https://support.microsoft.com/en-gb/help/899927.
*/
public class MicrosoftFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain filterChain) throws ServletException, IOException {
//Serve up a blank page to anything with a Microsoft Office user agent, forcing it to open the
//URL in a browser instead of trying to pre-fetch it, getting redirected to SSO, and losing
//the path of the original link.
if (!request.getHeader("User-Agent").contains("ms-office")) {
filterChain.doFilter(request, response);
}
}
}
/**
* Security configuration.
*/
#Configuration
public class SecurityConfiguration {
#Bean
public FilterRegistrationBean microsoftFilterRegistrationBean() {
FilterRegistrationBean<MicrosoftFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new MicrosoftFilter());
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
}
We are seeing a problem that TWO Chrome tabs are opened when clicking an URL from MS Word, and the page to open has JavaScript redirection: window.location.href=blabla
By debugging from the servers side, we confirmed that there are requests sent from Office app, besides Chrome. This is so wierd.
But anyway, by checking the request header "User-Agent", and returning an empty page to Office apps, our TWO tabs issue got resolved. That's definitely the right thing to do!
Here is my solution for this in WordPress. Add this to functions.php in your theme or another plugin file.
This may be helpful if your system, like WP, sends logged out users to a login page with a redirect to the page they were trying to access. Word was sending users to this page, but then WP wasn't properly handling the case where a user was already logged in. This code checks if there is a current user and a redirect_to param passed. If so, it redirects to the redirect_to location.
function my_logged_in_redirect_to()
{
global $current_user;
if($current_user->ID && $_REQUEST['redirect_to'])
{
wp_redirect($_REQUEST['redirect_to']);
exit;
}
}
add_action('wp', 'my_logged_in_redirect_to');
Here's a VBA fix, for Excel. The same concept can be applied for Microsoft Word. Basically, rather than firing off the link from within Excel, the code executes the link from within a shell.
Here's the code:
Private Sub Worksheet_FollowHyperlink(ByVal objLink As Hyperlink)
Application.EnableEvents = False
Dim strAddress As String
strAddress = "explorer " & objLink.TextToDisplay
Dim dblReturn As Double
dblReturn = Shell(strAddress)
Application.EnableEvents = True
End Sub
For the Excel sheet that contains the links, right-click the sheet tab and click View Code. The VBA editor appears.
Paste the code into the window, and close the editor.
Modify each link in the page so it simply points back to the cell that it is in. To do so:
Right-click the link, and click Edit Hyperlink. An Edit Hyperlink window appears.
Click Place In This Document.
Click the sheet name.
For Type the cell reference, enter a cell reference (e.g. A4).
Click OK.
A couple of notes:
You will need to save the spreadsheet as a macro-enabled spreadsheet
(.xlsm). When users open the spreadsheet, they will be asked to
enable macros. If they answer No, the links will not work.
These instructions are based on Excel 2010. Presumably later versions are similar.
I can't believe they call this a feature.
However, here's a featurefix for Apache:
RewriteEngine On
# Send a 200 to MS Office so it just hands over control to the browser
# It does not use existing session cookies and would be redirected to the login page otherwise
# https://www.wimpyprogrammer.com/microsoft-office-link-pre-fetching-and-single-sign-on/
RewriteCond %{HTTP_USER_AGENT} ;\sms-office(\)|;)
RewriteRule .* - [R=200,L]
Might not be best performance wise, as the whole page gets sent instead of an empty response, but I did not want to add another Apache modules just for fixing such an idio^H^H^H^H feature.
NGINX solution below:
if ($http_user_agent ~* Word|Excel|PowerPoint|ms-office) {
return 200 '<html><head><meta http-equiv="refresh" content="0"/></head><body></body></html>';
}
You can put it in the server or location block.
Works like charm.
I had to solve this issue for an ASP.NET site but I only wanted to use javascript/ jQuery:
var isCoBrowse = ('<%= Session["user"].ToString().ToLower() %>' != '0');
if (isCoBrowse && window.location.href.indexOf('ReturnUrl=') >= 0 && window.location.href.indexOf('dllCheq') == -1) {
//redirect to the ReturnUrl & add dllCheq to the URI
var toRedirect = decodeURIComponent(gup('ReturnUrl', window.location.href)) + '&dllCheq';
window.location = toRedirect;
}
I got the gup function from:
How to get the value from the URL parameter?
Use fix provided by microsoft given link below. https://support.microsoft.com/en-us/kb/218153
And in ColdFusion / Lucee
<cfif cgi.HTTP_USER_AGENT contains "Excel" OR cgi.HTTP_USER_AGENT contains "ms-office">
<cfabort/>
</cfif>
I suspect this is a matter of how you are setting the cookie(s).
Due to the nature of how the web was created, example.com is not seen as the same domain as www.example.com; hence: you can be logged in at www.example.com and not logged in at example.com.
So in other words, check the URL in your word or excel file - is it the same domain as how you are logged in within your browser?
There are two fixes/solutions to this cookie inconsistency:
1. redirect anyone who tries to load your site without the www. to the same page with the www. (or vice versa), or
2. when you are setting the cookie, make sure to specify the domain argument as ".example.com". The leading dot indicates the cookie should be valid on all subdomains of that domain as well.
I suspect the reason the browser eventually recognizes it is because you probably eventually end up landing on a URL with the same domain structure as how you are logged in.
Hope this helps.