Server.MapPath() with IIS URL Rewrite Module 2.0 - iis

I have a website in IIS, with a legacy classic asp application configured as a sub app.
I'm basically trying to create URL rewrite rules so that I don't have to change all of the relative URL's in the code.
e.g. URLS's such as "/themes/somedirectory" should be mapped to "/legacy/themes/somedirectory"
Using the URL Rewrite Module 2.0 I have a URL rewrite rule configured as follows:
<rule name="Reroute themes">
<match url="^themes.*" />
<action type="Rewrite" url="/legacy/{R:0}" />
</rule>
This works fine when navigating to the URL. However when using Server.MapPath(), it is not applying the rewrite rule.
Is Server.MapPath() actually supposed to take this into account? If not, how should I go about re-routing the application without modifying the code?

I was looking for the same thing so I gave it a try in a test app. It appears that Server.MapPath() does not acknowledge URL Rewrite Module rules.
Here is how I tested using an empty web project (Razor syntax):
Rewrite rule:
<system.webServer>
<rewrite>
<rules>
<rule name="Rewrite rule1 for test1">
<match url="^test1(.*)" />
<action type="Rewrite" url="{R:1}" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
cshtml:
<p>
The URL for this page is #Request.Url.AbsoluteUri .
<br />
MapPath of /test1 is #Server.MapPath("~/test1")
<br />
MapPath of / is #Server.MapPath("~/")
</p>
I hit http://localhost/, then http://localhost/test1. The results were:
The URL for this page is http://localhost/ .
MapPath of /test1 is c:\src\temp\test1
MapPath of / is c:\src\temp\
So looks like mappath is basically taking System.AppDomain.CurrentDomain.BaseDirectory (or something similar) and combining it with the relative URL. On a side note, I have separately confirmed that MapPath() takes into account 1 level of virtual directory, but not a 2nd (ie. virt pointing to another location that also has a virt defined).

I just had this problem, and for now am going with create a special MapPath variant that corresponds to my rewrite rule.
So either something like this:
string MapTheme(string themeName)
{
return Path.Combine(Server.MapPath("/legacy"), themeName)
}
Or, if you prefer:
string MapThemePath(string themeUrl)
{
Match m = Regex.Match("^themes/(.*)");
if (!m.Success)
throw new ArgumentException();
string themeName = m.Groups[1].Value;
return Path.Combine(Server.MapPath("/legacy"), themeName)
}
Or generalize:
string MyMapPath(string url)
{
Match m = Regex.Match("^themes/(.*)");
if (m.Success)
{
string themeName = m.Groups[1].Value;
return Path.Combine(Server.MapPath("/legacy"), themeName)
}
else if (itsAnotherSpecialRewriteCase)
{
return doSomeSimilarTransformation();
}
// ...
else
{
// Handle non-rewritten URLs
return Server.MapPath(url);
}
}
I don't especially like this, because it violates "do not repeat yourself".

Related

IIS: 502 when posting multipart/form-data and using ARR

We have a classic ASP.NET web api that is exposing a file upload endpoint. The file upload accepts a multipart/form-data request that holds the file. The format is:
POST https://dev.appname.com/api/v2/visitors/{{visitorId}}/attachments/upload
X-API-Key: {{apiKey}}
Content-Type: multipart/form-data; boundary=XXX
--XXX
Content-Disposition: form-data; name="image"; filename="filename.png"
Content-Type: image/png
{{ file bytes }}
--XXX--
We use the following rewriting:
<rule name="Rewrite to dev REST API" enabled="true" stopProcessing="true">
<match url="api/(v[0-9]+/.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" matchType="Pattern" pattern="(dev|dev-testing).appname.com" ignoreCase="true" negate="false" />
</conditions>
<action type="Rewrite" url="https://restapidev.appname.com/api/{R:1}?tenant={C:1}" appendQueryString="true" />
</rule>
So the url is rewritten from: https://dev.appname.com/api/v2/visitors/{{visitorId}}/attachments/upload to https://restapidev.appname.com/api/v2/visitors/{{visitorId}}/attachments/upload?tenant=dev
This gives us a response 502.
When hitting the https://restapidev.appname.com/api... url directly, the request is successful.
To diagnose the issue, I am writing the request body to a file:
private async Task SaveRequestBody() {
var req = HttpContext.Current.Request;
using var fileStream = File.OpenWrite($"C:\\temp\\{DateTime.Now:yyyy-MM-dd-HH-mm-ss}-UploadAttachment.txt");
await req.GetBufferedInputStream().CopyToAsync(fileStream);
}
I notice that:
When going through the dev.appname... url:
āŒ an empty file is written
When going through the restapidev.appname... url
āœ… the full request, including the upload is written to a file
When uploading a file without multipart/form-data (Content-Type: image/png, bytes directly posted in the request body)
āœ… the full request, including the upload is written to a file
Application logging seems to indicate that the application "hangs" on reading the request stream.
I have enabled failed request tracing, and noticed this:
At 12:36:37.144: GENERAL_READ_ENTITY_START
At 12:38:37.504: GENERAL_READ_ENTITY_END (2 minutes later!!)
BytesReceived="0", ErrorCode="The I/O operation has been aborted because of either a thread exit or an application request. (0x800703e3)"
FYI: There's a warning REWRITE_DISABLED_KERNEL_CACHE in the trace as well, but succesful requests have this warning as well.
I was not able to add the full log here (due to length restrictions on the post).
So our web application seems to "hang" while reading the request body:
only for an multipart/form-data upload
only when routed through ARR
Is there something that could be misconfigured?

Controller class xxxController could not be found error

I was migrating my web application to another server. Everything works fine except for viewing any uploaded file. It keeps showing the same error whenever I tried to view the uploaded file.
Updated :
eland\app\webroot\upload
Not Working --> <?php echo $this->Html->link(__('<i class="icon-file"></i>'), '../'.ELAND.'/upload/'.trim($rec['Bahanrujukan']['filename']), array('class' => 'btn btn-default btn-small','target'=>'_blank', 'escape' => false)); ?>
eland\app\webroot\img\imgs
Working --> <?php echo $this->Html->link(__('<i class="icon-file"></i>'), '../'.ELAND.'/img/imgs/'.trim($rec['Bahanrujukan']['filename']), array('class' => 'btn btn-default btn-small','target'=>'_blank', 'escape' => false)); ?>
Should I check the plugin or the controller?
It turns out that, the issue was misconfiguration in web.config. During translation from Apache (.htaccess) to IIS (web.config), the 'upload' folder was not granted for access to the webroot.
<rule name="Rewrite routed access to assets(img, css, files, js, favicon)" stopProcessing="true"> <match url="^(img|css|files|js|upload|favicon.ico)(.*)$" /> <action type="Rewrite" url="webroot/{R:1}{R:2}" appendQueryString="false" /></rule>
thanks guys for helping me out!

IIS ReWrite catch .jpg?w=960&h=980

I have created IIS Outbound Rules to rewrite to CDN. Example for .mov files
<rule name="CDN-01-mov" preCondition="CheckHTML" stopProcessing="true">
<match filterByTags="Img, CustomTags" customTags="src" pattern="http(s)?://www.(example.com)(/public)(/uploads)(.*\.mov)" />
<action type="Rewrite" value="https://cdn.example.com/public/uploads{R:5}" />
</rule>
However, I would also like to catch .jpg files. The problem is that the tags with .jpg files in my application are like this:
files/storage/327/9071615039504vishbjwcgbftdy2my1p6.jpg?w=960&h=980
so it has the ?w=960&h=980 part which I don't know how to catch with regex.
How could I make a regex rule to catch .jpg[anything] ?
Thanks
Alex
The character before matching .jpg is R1, the character matching .jpg is R2, and the character string after .jpg is R3.
This is Pattern:
(.*)(.jpg)(.*)
Here is for your reference: Regular Expression Language - Quick Reference

Yii2 Framework to Azure Web App (404 Page Not Found)

Thank for reading my post.
I'm having an issue making my Website Application(Yii2) works correctly in Azure Web Apps. I've migrated my Yii2 Websites from an existing server to the Azure Web Apps. After lots of manipulation listed below, Iā€™m able to access the Website.
The main theme loads successfully but throwing "404 Page not found
The requested page is missing, or the address has been changed" Error in the body and others links in the "Menu Bar" not working too. "The resource you are looking for has been removed, had its name changed, or is temporarily unavailable."
The Azure Resources are configured as below:
1 x App Service Plan : S1:1 (Windows Base)
1 x Azure Database for MySQL server
1 x App Service (The Web App)
App Service Application Setting:
.Net Framwork: v4.7
PHP Version: 7.0
Platform: 32bit
Migration Steps:
FTP all files/folder from htdocs in my existing server to my App Service Plan (\site/wwwroot)
Generate the SQL Table creation in PhpAdmin
Find and Replace ENGINE=InnoDB DEFAULT CHARSET=utf8; in the script
Connect to Azure Database for MySQL server, create new Schema and Run the Script
From Azure, KUDU Inferface browse (\site\wwwroot\config) and change the db.php to
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=xxxx.mysql.database.azure.com;dbname=xxxxx',
'username' => 'xxxxxxx#xxxxxxxxxxxxxxxxxx',
'password' => 'xxxxxx',
'charset' => 'utf8',
];
Restart the Web App
Check the https://yourdomain.com/requirements.php (Passed without any Error)
"The resource you are looking for has been removed, had its name changed, or is temporarily unavailable" when trying to browse the new Web App.
KUDO PowerShell windows browse back to site/wwwroot and executed the following line of codes
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php
php composer.phar global require "fxp/composer-asset-plugin:^1.2.0"
Browse to the Directory (\site\wwwroot\web) and change index.php with the following line of codes:
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
if(!headers_sent()) {
header("Status: 301 Moved Permanently");
header(sprintf(
'Location: https://%s%s',
$_SERVER['HTTP_HOST'],
$_SERVER['REQUEST_URI']
));
exit();
}
}
// comment out the following two lines when deployed to production
('YII_DEBUG') or define('YII_DEBUG', false);
defined('YII_ENV') or define('YII_ENV', 'prod');
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
$config = require(__DIR__ . '/../config/web.php');
(new yii\web\Application($config))->run();
From the Azure Portal / Web App / Application settinh, .change the default directory from site\wwwroot to site\wwwroot\web
Restart the Web App.
The home page them now loads successfully but with a 404 Error within the body and "The resource you are looking for has been removed, had its name changed, or is temporarily unavailable." when trying to access other pages in the header.
I also noted that I have 2 .htacss file
1x in my \site\wwwroot and 1x in my \site\wwwroot\web
Haved tried deleting them and configure a web.config file in (site\wwwroot\web) but still not working.
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect rquests to default azure websites domain" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTP_HOST}" pattern="^yoursite\.azurewebsites\.net$" />
</conditions>
<action type="Redirect" url="https://mysitename.azurewebsites.net/{R:0}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
As Yii2 is not famous in Azure Web App, can't find a solution anywhere. Will appreciate if you can help along.

Removing Server version from Response Headers using URL Rewrite

I have used the information from Remove Unwanted HTTP Response Headers to remove IIS server version from Response Headers.
Add the Server Variable
Create the following outbound rule:
<rewrite>
<outboundRules>
<rule name="Remove Server" patternSyntax="ExactMatch">
<match serverVariable="RESPONSE_SERVER" pattern=".*" />
<action type="Rewrite" />
</rule>
</outboundRules>
</rewrite>
Though the code works fine and URL Rewrite is removing the server version successfully, the integration of the same is screwing up couple of pages in my legacy classical ASPX website as in:
With URL Rewrite:
fa 7 RepCube 8a | Default Measure: 6b Not Set 4e | Size: 84.28Mb
b3 65 c1 130 6 FY2014 bd 78 9 Processed 76 6 Actual 76 10 Jan-14 To Dec-14 1 76 Delete
Without URL Rewrite:
RepCube | Default Measure: Not Set | Size: 84.28Mb
FY2014 Processed Actual 10 Jan-14 To Dec-14 Delete
All the data that is getting generated are from the Classical ASPX page with Server side redirects as in <% tags.
Can you please help me understand what can be the problem with the same?

Resources