Rewrite urls from user submitted HTML - asp.net

I use one WYSIWYG editor in a small cms. It allows users to upload files, images, etc. If I add image named dog.jpg, in source I'll get:
<img src="/myweb/userfiles/images/dog.jpg" />
I can save this to a database and use it later on any page, until I move my site to a live domain.
myweb is virtual directory in IIS. "/" points to root, in this case localhost, so I have to use "/myweb". However when I upload site to server and copy database there, all links will be broken, because there is no "myweb" folder on server.
My idea was to replace "/myweb" on save with empty string. I also have to replace full url, which editor creates for some files. On display I would have to add correct Application dir. I would probably save both versions in database, and only on server change force display version to update.
By now I've come up with:
p = p.Replace("href=\"" + fullUrl, "href=\"").Replace("src=\"" + fullUrl, "src=\"").Replace("href=\"" + partialUrl, "href=\"").Replace("src=\"" + partialUrl, "src=\"");
Which is ugly, hard to maintain and inefficient. I guess better approach would be to use regex, but I don't know how to do it.
My question is, can anyone recommend good article, blog/forum post on this? If you have other solution, great.

I am unsure the regex version has any of the characteristics you mention in this case.
That said, you can do:
string ReplaceUrlPaths(string html, string partialPath, string fullPath)
{
var pattern = string.Format("((href|src)=\")({0}|{1})", partialPath, fullPath);
var regex = new Regex(pattern);
return regex.Replace(html, m => m.Groups[1].Value);
}
[TestMethod]
public void TestMethod10()
{
var input = #"<img src=""/myweb/userfiles/images/dog.jpg"" />";
//carefull with any special regex char in the paths
var replaced = ReplaceUrlPaths(input, "/myweb", "/some/full/path");
Assert.AreEqual(
#"<img src=""/userfiles/images/dog.jpg"" />",
replaced);
}
If you are proceeding with that, refactor it to instantiate the regex once with the compile option(as the partialPath and fullPath won't be changing).
Also consider avoiding it all, by defining a web site with an alternate port to just have it as a root Url.

Store the local root path separately from the images. For each image, store the relative path to that image.
When displaying images locally, use the local root merged with the relative path. When you publish to the remote server, you add the remote root to the relative path.

Does your WYSIWYG editor allow you to configure the base URL e.g. so that paths to images can use relative paths? I think the FCKEditor has something like FCKConfig.BaseHref in it's config file that does something like this.
Alternatively can you run the site as a root site using the ASP.NET 2.0 web server? Then you wouldn't have to worry about rewriting paths to images as you could just use paths from the webroot.

Related

Relative path for a included file - ASP/HTML

Sorry if this question is answered somewhere else but I tried searching several pages and was unsuccessful.
So i have an include file (sidebar) which i am using in all pages.
Default.asp
Products.asp
Salary/Survey.asp
inc/sidebar.asp (this is the included file)
now inside sidebar.asp I have a link for Salary/Survey.asp
from all other pages at root level, i can simply use href='Salary/Survey.asp' and will work fine. but when I am on page Survey.asp , writing href='Salary/Survey.asp' will become actually Salary/Salary/Survey.asp. I understand it has to be ../Salary/Survey.asp to be used properly but it will then not work for root level pages.
I can not use root relative which is /Default.asp and /Salary/Survey.asp as I am working for someone else' project and i dont know his directory structure and thus i only have option to document relative path.
Hope this is clear to understand and someone helps me out.
Thanks!
We solved this problem the following way...
Each of our asp pages included a special file that Dims and sets golbal variables. We called ours Info.asp
Inside Info.asp we defined a variable called strRelativePath
Dim strRelativePath
strRelativePath = ""
Every asp page set the relative path according to it relative position:
for example:
Root pages - strRelativePath = ""
One level deep pages - strRelativePath = "../"
Two levels deep pages - strRelativePath = "../../"
Then it was a matter of prefacing all the links requiring a relative path with <%=strRelativePath%>
you need to get write this after the that - Salary/Survey.asp
You can get the virtual path to the file from one of several server variables - try either:
Request.ServerVariables("PATH_INFO")
Request.ServerVariables("SCRIPT_NAME")
Either server variable will give you the virtual path including any sub-directories and the file name - given your example, you'll get /virtual_directory/subdirectory/file.asp. If you just want the virtual directory, you'll need to strip off everything after the second forward slash using whatever method you prefer for plucking a directory out of a path, such as:
s = Request.ServerVariables("SCRIPT_NAME")
i = InStr(2, s, "/")
If i > 0 Then
s = Left(s, i - 1)
End If
or:
s = "/" & Split(Request.ServerVariables("SCRIPT_NAME"), "/")(1)
basically, if your sidebar can be included from programs in different folders, the only 'easy' way is to use absolute paths like you mentioned.
You say can't use it, so I would think of different ways...
virtual folders: In IIS you could set a virtual folder in salary folder for 'salary' and point it to the site's root.
OS links (similar to above, but at the OS level)
use mappath. You could check mappath to see the actual folder you're in, and use the correct include (with/without /salary) though I'm thinking this might give you an error, not sure.

Persits.MailSender.4 error '800a0007' upon calling objMail.AddEmbeddedImage

I'm using Persits AspEmail for sending emails in a Classic ASP application. I've used it many times before but I had never come across the following issue:
I need to embed an image into the body of an email, but this image is actually virtual (I'm using IIS Rewrite to handle all URL rewrites, so when an image is requested from a specific directory, IIS Rewrite calls an .asp page that displays the image using the Persits AspJpeg component), but when I try to do it, AspEmail returns this error:
Persits.MailSender.4 error '800a0007'
The system cannot find the path specified.
Any other image that is not virtual will get embedded.
The code is simple:
Set objMail = Server.CreateObject("Persits.MailSender")
...
objMail.AddEmbeddedImage virtualImageUrl, virtualImageCid
...
objMail.Send
Am I doing something wrong here? If AspEmail can't handle virtual files, is there a way around this? Please, other than using FSO to temporarily copy the file to a directory in order to embed it, or leaving the image on the server -- I really need it to be embedded.
Thank you (a lot!) in advance,
Cheers,
Mark
P.S.: My server is running IIS 7.5 / IIS Rewrite Module 2 / AspEmail v5.1.0.3.
AddEmbeddedImage property needs a physical path. And it doesn't make an http request (to getting dynamic script response).
4.2 The AddEmbeddedImage Method (http://www.aspemail.com/manual_04.html#4_2)AspEmail offers support for embedded images via the method AddEmbeddedImage which takes two arguments:
the physical path to an image file, and its Content ID, which is simply an
arbitrary string without spaces.If your message contains multiple
embedded images, each must be assigned a unique Content ID.
But there is another property more appropriate than AddEmbeddedImage to using dynamic images.
You need make an http request and pass the response to your AspEmail instance using AddEmbeddedImageMem property.
Similar solution: embed google qrcode in email
Here's what I did:
Since I'm also using Persits AspJpeg to generate the virtual image, I used the objAspJpeg.Binary property to save the image temporarily to a variable, and then passed this variable to objMail.AddEmbeddedImageMem method, and voilĂ .
'First: AspJpeg to process and generate the virtual binary image.'
Set objAspJpeg = Server.CreateObject("Persits.Jpeg")
objAspJpeg.Open(Server.MapPath(physicalImgUrl)) 'Actual, physical image.'
'...some image processing: resizing, etc...'
processedVirtualImg = objAspJpeg.Binary 'Generated virtual image.'
Set objAspJpeg = Nothing
'Second: AspEmail to embed the virtual image and send the email.'
Set objMail = Server.CreateObject("Persits.MailSender")
objMail.Host = "www.example.com"
'< the rest of the config parameters here >'
objMail.Body = "<img src=""cid:virtualImgId"" />"
objMail.IsHTML = True
objMail.AddEmbeddedImageMem "image.jpg", "virtualImgId", processedVirtualImg
objMail.Queue = True
objMail.Send
Set objMail = Nothing

stupid caching in asp.net

i use such code
string.Format("<img src='{0}'><br>", u.Avatar);
u.Avatar-it's like '/img/path/pic.jpg'
but in this site i can upload new image instead old pic.jpg. so picture new, but name is old. and browser show OLD picture (cache). if i put random number like /img/path/pic.jpg?123 then works fine, but i need it only ufter upload, not always. how can i solve this?
string imgUrl = _
string.Format("<img src='{0}?{1}'><br>", _
u.Avatar, _
FunctionThatLookupFileSystemForItsLastModified(u.Avatar).Ticks.ToString());
Instead of linking to the images directly, consider setting up a generic HTTP handler to serve the images.
MSDN: HTTP Handlers and HTTP Modules Overview
Stack Overflow: How to use output caching on .ashx handler
Append DateTime.Now.Ticks to the image url:
string imgUrl =
string.Format("<img src='{0}?{1}'><br>", u.Avatar,DateTime.Now.Ticks);
EDIT: I don' think this best practice are even a practice I would use. This is just a suggestion given the limited information given in case the Random implementation isn't truly Random.
Read your post again,,, sorry for general answer.
To workaround it do following
On Application_Start create a Dictionary with uploaded images save it on Application object, set it to null. Once you upload an image add it to this Dictionary. Wrap every place avatars appear on your website with function that evaluates image in Dictionary if found return imagename.jpg?randomnumber and then delete it from a Dictionary else return just an imagename.jpg.
This is going to be heavy because you will need to check each image in Dictionary but this will do exactly what you need.
You can set cache dependancy using the System.Web.Caching.CacheDependency namespace.
This can set the dependancy on the file uploaded, and will release the cache for that file automatically when the file changes.
There are lots of articles and stuff on MSDN and other places so I will not go into details on all that level of detail.
You can do inserts, deletes and other management of cache using the tools available.
(and this does not require you to change the file names or tack on stuff - it knows by the file system that the file changed)

What is the most efficient way to perform the reverse of Server.MapPath in an ASP.Net Application

I am building an MVC application in which I am reading a list of files from the file system and I want to pass the relative URL to that file to the view, preferably prefixed with "~/" so that whatever view is selected cab render the URL appropriately.
To do this, I need to enumerate the files in the file system and convert their physical paths back to relative URLs. There are a few algorithms I've experimented with, but I am concerned about efficiency and minimal string operations. Also, I believe there's nothing in the .Net Framework that can perform this operation, but is there something in the latest MVC release that can?
At the moment I don't know any built-in method to do it, but it's not difficult, I do it like this:
We need to get the Application root, and replace it in our new path with ~
We need to convert the backslashes to slashes
public string ReverseMapPath(string path)
{
string appPath = HttpContext.Current.Server.MapPath("~");
string res = string.Format("~{0}", path.Replace(appPath, "").Replace("\\", "/"));
return res;
}
Isn't this what UrlHelper.Content method does? http://msdn.microsoft.com/en-us/library/system.web.mvc.urlhelper.content.aspx
I did some digging, trying to get the UrlHelper class to work outside of a controller, then I remembered a old trick to do the same thing within an aspx page:
string ResolveUrl(string pathWithTilde)
Hope this helps!
See:
https://msdn.microsoft.com/en-us/library/system.web.ui.control.resolveurl(v=vs.110).aspx

Get virtual path for a full path in asp classic

How can I get the virtual path for a full path in ASP classic. Note that the full path may be under a virtual directory and therefore the simplistic
virtPath = Replace(fullPath, Server.MapPath("/"), "")
method will not work.
Edit: To clarify, an example follows
Full Windows File Path (known):
\\MyServer\MyShare\Web\Site\Logs\Test.txt
My Website has a Virtual directory
called Logs that Points to \\MyServer\MyShare\Web\Site\Logs\.
Virtual Path (unknown): /Logs/Text.txt
Http path (unknown, needed):
http://Site/Logs/Test.txt
The code is in a asp page in the main app, not under any virtual directories. It is located on a separate server from the file in question.
IIS 6.0
How do I find the virtual path from the full file path?
In case anyone's interested, Anthony Jones' answer showed me the way to getting the application's relative root consistently. So if you have a site at http://example.com and a local development equivalent at http://localhost/example, you can find your root with this function:
Function ToRootedVirtual(relativePath)
Dim applicationMetaPath : applicationMetaPath = Request.ServerVariables("APPL_MD_PATH")
Dim instanceMetaPath : instanceMetaPath = Request.ServerVariables("INSTANCE_META_PATH")
Dim rootPath : rootPath = Mid(applicationMetaPath, Len(instanceMetaPath) + Len("/ROOT/"))
ToRootedVirtual = rootPath + relativePath
End Function
You can then call it like this to get the root path:
ToRootedVirtual("/")
Which will return:
/ on example.com
/example/ on localhost/example
You can also use it without the slash:
ToRootedVirtual("")
If I've understood the question.
Assumption
The full path is a path with in the current application or a child application. It is not a path limited to the parent nor a path into a sibling application. The desired path is relative to the current applications path.
Scenario 1
A path such as
"/someApp/someFolder/someSubFolder/file.ext"
should resolve it to:-
"~/someFolder/someSubFolder/file.ext"
(although the ~/ notation isn't something ASP classic understands).
Scenario 2
"/someApp/someSubApp/SomeSubFolder/file.ext"
you still want:-
"~/someFolder/someSubFolder/file.ext"
Scenario 3
The app is the root application of the site:-
"/someFolder/someSubFolder/file.ext"
would still become
"~/someFolder/someSubFolder.file.ext"
Solution
The key to solving this is:-
Dim sAppMetaPath : sAppMetaPath = Request.ServerVariables("APPL_MD_PATH")
For the above set of scenarios this will result in something like:-
"/LM/W3SVC/33230916/Root/someApp"
"/LM/W3SVC/33230916/Root/someApp/someSubApp"
"/LM/W3SVC/33230916/Root"
Also
Dim sInstanceMetaPath: sInstanceMetaPath = Request.ServerVariables("INSTANCE_META_PATH")
will in all the scenarios return
"/LM/W3SVC/33230916"
With some mathematical reduction we can arrive at the function:-
Function ToAppRelative(virtualPath)
Dim sAppMetaPath : sAppMetaPath = Request.ServerVariables("APPL_MD_PATH")
Dim sInstanceMetaPath: sInstanceMetaPath = Request.ServerVariables("INSTANCE_META_PATH")
ToAppRelative = "~/" & Mid(virtualPath, Len(sAppMetaPath) - Len(sInstanceMetaPath) - 3)
End Function
Although there may be a better way, I always did this by creating a config variable where I manually specify the root path that is not part of the virtual path. This is because you do not know if the site will be deployed as root, under a folder in root web, or in a virtual directory.
well, my answer isn't better than OrbMan's...
I have organized my app in such a way that every include is relative...
that is
instead of \myapp\lib\somefile.asp I use ..\lib\somefile.asp
in other cases I just do what Orbman said...
Here's how you solve root-relatie pathing in html via ASP so your site can be portable to different hosting directories.
This little snippet will produce the correct prefix to set your URLs:
Mid(Request.ServerVariables("APPL_MD_PATH"),Len(Request.ServerVariables("INSTANCE_META_PATH"))+6)
You can use this in LINKs, IMGs, hyperlinks, etc as follows:
<link href="<%= Mid(Request.ServerVariables("APPL_MD_PATH"),Len(Request.ServerVariables("INSTANCE_META_PATH"))+6) %>/assets/css/master.css" rel="stylesheet" type="text/css" />
so, code your paths to be root-relative (starts with a /) and then put this snippet right in front of that first slash, inside the quotes:
The server's virtual path is:
<%Response.Write "http://" & Request.ServerVariables("server_name") &
left(Request.ServerVariables("SCRIPT_NAME"),InStrRev(Request.ServerVariables("SCRIPT_NAME"),"/")) %>
</p>

Resources