29

I've got a major brainteaser.

I want to open a file in classic ASP. I'm using various variables because things can change but the outcome is correct. I know this because I've tested the outcome by copying the linkadress and placing it in my URL. Now the problem: If I click my link it doesn't do anything. Not a refresh, not a redirect. nothing. Does anyone know what I did wrong?

Ok here's the deal. My file isn't always local, it depends on what environment I'm on. If I copy-paste the outcome of my url it does download. If I click my URL it doesn't respond. Any ideas? Browser problem? (although I've tested 5 browsers) Or anything else? I'm really stuck here and the internet does not seem to be on my side.

I've got 3 environments. The variables underneath here are so that the link works. I know the link works because I've tested it by copying. And yes, it does begin with file:/// and yes I'm sure the link is right.

Here's my line of code:

response.write("<td class='tab_kolom2'><a href='"&rootRs("pre_rootpad")&rootRs("rootpad_protocollen")&"\"&overzichtRs("Formuliernr")&"\Uitvoeringsoverzicht.xls' target='_blank' download>Click here</a></td>")

EDIT: Screenshot with error/outcome of link

error

user692942
  • 16,398
  • 7
  • 76
  • 175
Benny Niemeijer
  • 349
  • 1
  • 3
  • 15
  • 1
    Perhaps just `"_blank"` instead of `"_new window"` for the target? – Paul Jan 20 '16 at 14:36
  • @Paul tried it, doesn't work either – Benny Niemeijer Jan 20 '16 at 14:45
  • And you're certain that there are values in the `rootRs` and `overzichtRs`? – Paul Jan 20 '16 at 15:07
  • 5
    Please "view source" of your output and paste the HTML of the output line for us so we can see the values in your recordsets. Also, you appear to be using \backslashes\ instead of /forward/slashes/ – Rich Jan 20 '16 at 15:12
  • @Rich See my updated post for the HTML output. Backslashes or forwardslashes don't matter They work eitherway. Also, when I paste the link in past browser it does work. It's only the link which doesn't work – Benny Niemeijer Jan 21 '16 at 07:22
  • That output shows a link starting with `C:\ ` haven't people already explained that will not work in a browser, did you even try `file:///C:\ `? – user692942 Jan 25 '16 at 10:34
  • @Lankymart yep, tried and worked if I pasted it in my browser. – Benny Niemeijer Jan 25 '16 at 10:54
  • Yes, it will *(depending on the browser)* but that still doesn't mean it will work from a link. They are not "like for like" and that assumption you are making is why you've been getting so frustrated with the people trying to help you. – user692942 Jan 25 '16 at 10:57
  • Appreciate trying to make the question clearer but we don't know what is inside `rootRs("pre_rootpad")` and `rootRs("rootpad_protocollen")` so showing that code doesn't help. What we need to see is the generated HTML output *(source as @Rich suggested)* and ideally one that doesn't start `C:\ `. – user692942 Jan 25 '16 at 11:03
  • @Lankymart, I appreciate you keep helping me. I know I can be a real pain in the ass sometimes. I'm off duty now but I'll come back to this tomorrow. – Benny Niemeijer Jan 25 '16 at 12:05
  • @Lankymart Edited with different screenshot. – Benny Niemeijer Jan 26 '16 at 08:04

6 Answers6

19

Now we know what the actual error is can formulate an answer.

Not allowed to load local resource

is a Security exception built into Chrome and other modern browsers. The wording may be different but in some way shape or form they all have security exceptions in place to deal with this scenario.

In the past you could override certain settings or apply certain flags such as

--disable-web-security --allow-file-access-from-files --allow-file-access

in Chrome (See https://stackoverflow.com/a/22027002/692942)

It's there for a reason

At this point though it's worth pointing out that these security exceptions exist for good reason and trying to circumvent them isn't the best idea.

There is another way

As you have access to Classic ASP already you could always build a intermediary page that serves the network based files. You do this using a combination of the ADODB.Stream object and the Response.BinaryWrite() method. Doing this ensures your network file locations are never exposed to the client and due to the flexibility of the script it can be used to load resources from multiple locations and multiple file types.

Here is a basic example ("getfile.asp"):

<%
Option Explicit

Dim s, id, bin, file, filename, mime

id = Request.QueryString("id")

'id can be anything just use it as a key to identify the 
'file to return. It could be a simple Case statement like this
'or even pulled from a database.
Select Case id
Case "TESTFILE1"
  'The file, mime and filename can be built-up anyway they don't 
  'have to be hard coded.
  file = "\\server\share\Projecten\Protocollen\346\Uitvoeringsoverzicht.xls"     
  mime = "application/vnd.ms-excel"
  'Filename you want to display when downloading the resource.
  filename = "Uitvoeringsoverzicht.xls"

'Assuming other files 
Case ...
End Select

If Len(file & "") > 0 Then
  Set s = Server.CreateObject("ADODB.Stream")
  s.Type = adTypeBinary 'adTypeBinary = 1 See "Useful Links"
  Call s.Open()
  Call s.LoadFromFile(file)
  bin = s.Read()

  'Clean-up the stream and free memory
  Call s.Close()
  Set s = Nothing

  'Set content type header based on mime variable
  Response.ContentType = mime
  'Control how the content is returned using the 
  'Content-Disposition HTTP Header. Using "attachment" forces the resource
  'to prompt the client to download while "inline" allows the resource to
  'download and display in the client (useful for returning images
  'as the "src" of a <img> tag).
  Call Response.AddHeader("Content-Disposition", "attachment;filename=" & filename)
  Call Response.BinaryWrite(bin)
Else
  'Return a 404 if there's no file.
  Response.Status = "404 Not Found"
End If
%>

This example is pseudo coded and as such is untested.

This script can then be used in <a> like this to return the resource;

<a href="/getfile.asp?id=TESTFILE1">Click Here</a>

The could take this approach further and consider (especially for larger files) reading the file in chunks using Response.IsConnected to check whether the client is still there and s.EOS property to check for the end of the stream while the chunks are being read. You could also add to the querystring parameters to set whether you want the file to return in-line or prompt to be downloaded.


Useful Links

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
user692942
  • 16,398
  • 7
  • 76
  • 175
  • That would explain why it does work on old computers. Thanks! – Benny Niemeijer Jan 26 '16 at 15:21
  • 1
    @BennyNiemeijer The above method will work an any as it negates the risk of exposing local file systems and network paths. The server does the heavy lifting not the client. Just make sure that the account the Classic ASP web application is running as has the appropriate permissions to access the file locations you wish to read from. – user692942 Jan 26 '16 at 15:26
  • Thanks, It did the trick. Only thing now is it opens as "_getfile.xls_" Could I change the name? – Benny Niemeijer Jan 27 '16 at 10:42
  • 1
    @BennyNiemeijer Yes the `Content-Disposition` HTTP header can do this for you, I'll update my example. – user692942 Jan 27 '16 at 11:28
  • 1
    Thank, Worked as it should now. Finally this case can be closed, couldn't do it without your help so thanks a lot! – Benny Niemeijer Jan 27 '16 at 11:56
  • This answer appears to answer my issue also for file opening and downloads, but I am also experiencing issues with uploading a file using classic ASP in the current versions of Chrome and Edge. Would using an ADODB.STREAM object work on uploads as well? – JNickVA1 Jan 05 '23 at 15:11
11

For people do not like to modify chrome's security options, we can simply start a python http server from directory which contains your local file:

python -m SimpleHTTPServer

and for python 3:

python3 -m http.server

Now you can reach any local file directly from your js code or externally with http://127.0.0.1:8000/some_file.txt

alioguzhan
  • 7,657
  • 10
  • 46
  • 67
5

You will have to provide a link to your file that is accessible through the browser, that is for instance:

<a href="http://my.domain.com/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">

versus

<a href="C:/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">

If you expose your "Projecten" folder directly to the public, then you may only have to provide the link as such:

<a href="/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">

But beware, that your files can then be indexed by search engines, can be accessed by anybody having this link, etc.

gpinkas
  • 2,291
  • 2
  • 33
  • 49
  • It's on a local machine, the variables are different on my test and production environment (which are inranet environments) and can only be accessed by people who have the right rights. Files on the test and production environments are linked to a server where the documents are (hence the rootpad variables) Only you're missing the point of the question which is: My link is right, it just doesn't respond. Why is that? – Benny Niemeijer Jan 22 '16 at 08:07
  • 2
    A link starting with "C:/..." is not valid, as @Rich said in his answer, you could format the link like "file:///C:/...", but this would work ONLY on your own machine, because f.i. on my machine, there is no C: drive. The link must point to a folder accessible via IIS. Similar answer here: http://stackoverflow.com/a/28170154/911635 – gpinkas Jan 25 '16 at 08:47
  • Did you check if any other link works, i.e. it's not a "browser"/styling/javascript problem? – gpinkas Jan 25 '16 at 09:59
1

Follow the below steps,

  1. npm install -g http-server, install the http-server in angular project.
  2. Go to file location which needs to be accessed and open cmd prompt, use cmd http-server ./
  3. Access any of the paths with port number in browser(ex: 120.0.0.1:8080) 4.now in your angular application use the path "http://120.0.0.1:8080/filename" Worked fine for me
Saba Mulla
  • 11
  • 1
0

I didn't realise from your original question that you were opening a file on the local machine, I thought you were sending a file from the web server to the client.

Based on your screenshot, try formatting your link like so:

<a href="file:///C:/Projecten/Protocollen/346/Uitvoeringsoverzicht.xls">Klik hier</a>

(without knowing the contents of each of your recordset variables I can't give you the exact ASP code)

Rich
  • 378
  • 7
  • 18
  • It's not that the link isn't right, it's that it doens't repond. – Benny Niemeijer Jan 21 '16 at 10:09
  • 4
    @BennyNiemeijer It ***"doesn't respond"*** because it isn't right, seriously people are trying to help you here. Honestly I don't know why they bother with the attitude you have displayed. Just because a link works for you outside of a browser doesn't mean it's valid within one. All local files links have to begin with `file:///` otherwise the browser will not understand it is a local file resource. They may also find accessing what is classed as a local resource may be restricted by some browsers if running with default configuration values. – user692942 Jan 25 '16 at 10:18
  • I don't even know why I bother to keep answering the same (wrong) answer. I tried everything with file:/// and not, tried 5 different browser. Nothing is working. If this is something that used to work (It works on old computers on my work) but it doesn't anymore, so be it. But I know my link is right. Period. And if I stated it multiple times I kinda loose my temper. Not that hard to understand right? – Benny Niemeijer Jan 25 '16 at 10:27
  • 6
    @BennyNiemeijer Actually yes and I'll tell you why. You keep going on about what you have tried but you don't show that in the question, until you update the question and show what you have tried people will continue to make the same suggestions to your frustration. The screenshot you took shows a `` pointing to `C:\....` which has been stated multiple times will not work, update the question or continue to have people second guessing you. – user692942 Jan 25 '16 at 10:32
-1

You just need to replace all image network paths to byte strings in HTML string. For this first you required HtmlAgilityPack to convert Html string to Html document. https://www.nuget.org/packages/HtmlAgilityPack

Find Below code to convert each image src network path(or local path) to byte sting. It will definitely display all images with network path(or local path) in IE,chrome and firefox.

string encodedHtmlString = Emailmodel.DtEmailFields.Rows[0]["Body"].ToString();

        // Decode the encoded string.
        StringWriter myWriter = new StringWriter();
        HttpUtility.HtmlDecode(encodedHtmlString, myWriter);
        string DecodedHtmlString = myWriter.ToString();

        //find and replace each img src with byte string
         HtmlDocument document = new HtmlDocument();
         document.LoadHtml(DecodedHtmlString);
         document.DocumentNode.Descendants("img")
          .Where(e =>
        {
            string src = e.GetAttributeValue("src", null) ?? "";
            return !string.IsNullOrEmpty(src);//&& src.StartsWith("data:image");
        })
        .ToList()
                    .ForEach(x =>
                    {
                        string currentSrcValue = x.GetAttributeValue("src", null);                                
                        string filePath = Path.GetDirectoryName(currentSrcValue) + "\\";
                        string filename = Path.GetFileName(currentSrcValue);
                        string contenttype = "image/" + Path.GetExtension(filename).Replace(".", "");
                        FileStream fs = new FileStream(filePath + filename, FileMode.Open, FileAccess.Read);
                        BinaryReader br = new BinaryReader(fs);
                        Byte[] bytes = br.ReadBytes((Int32)fs.Length);
                        br.Close();
                        fs.Close();
                        x.SetAttributeValue("src", "data:" + contenttype + ";base64," + Convert.ToBase64String(bytes));                                
                    });

        string result = document.DocumentNode.OuterHtml;
        //Encode HTML string
        string myEncodedString = HttpUtility.HtmlEncode(result);

        Emailmodel.DtEmailFields.Rows[0]["Body"] = myEncodedString;