Skip to content

Commit e0bdc37

Browse files
committed
Added helper to create HttpWebRequest instances for safe local calls (unfinished)
1 parent bf189be commit e0bdc37

6 files changed

Lines changed: 109 additions & 63 deletions

File tree

src/Libraries/SmartStore.Core/Utilities/FileDownloadManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public FileDownloadResponse DownloadFile(string url, bool sendAuthCookie = false
3737

3838
url = WebHelper.GetAbsoluteUrl(url, _httpRequest);
3939

40-
var req = (HttpWebRequest)WebRequest.Create(url);
40+
var req = WebRequest.CreateHttp(url);
4141
req.UserAgent = "SmartStore.NET";
4242

4343
if (timeout.HasValue)

src/Libraries/SmartStore.Core/WebHelper.cs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ namespace SmartStore.Core
1818
{
1919
public partial class WebHelper : IWebHelper
2020
{
21+
private static object s_lock = new object();
2122
private static bool? s_optimizedCompilationsEnabled;
2223
private static AspNetHostingPermissionLevel? s_trustLevel;
2324
private static readonly Regex s_staticExts = new Regex(@"(.*?)\.(css|js|png|jpg|jpeg|gif|bmp|html|htm|xml|pdf|doc|xls|rar|zip|ico|eot|svg|ttf|woff|otf|axd|ashx|less)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
2425
private static readonly Regex s_htmlPathPattern = new Regex(@"(?<=(?:href|src)=(?:""|'))(?!https?://)(?<url>[^(?:""|')]+)", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
2526
private static readonly Regex s_cssPathPattern = new Regex(@"url\('(?<url>.+)'\)", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Multiline);
27+
private static string s_safeLocalHostName = null;
2628

2729
private readonly HttpContextBase _httpContext;
2830
private bool? _isCurrentConnectionSecured;
@@ -631,20 +633,20 @@ public static string GetPublicIPAddress()
631633

632634
if (string.IsNullOrEmpty(result))
633635
{
634-
foreach (var checker in checkers)
636+
using (var client = new WebClient())
635637
{
636-
try
638+
foreach (var checker in checkers)
637639
{
638-
using (var client = new WebClient())
640+
try
639641
{
640642
result = client.DownloadString(checker).Replace("\n", "");
641643
if (!string.IsNullOrEmpty(result))
642644
{
643645
break;
644646
}
645647
}
648+
catch { }
646649
}
647-
catch { }
648650
}
649651
}
650652

@@ -671,5 +673,56 @@ public static string GetPublicIPAddress()
671673

672674
return result;
673675
}
676+
677+
public static HttpWebRequest CreateHttpRequestForSafeLocalCall(Uri requestUri)
678+
{
679+
Guard.ArgumentNotNull(() => requestUri);
680+
681+
EnsureSafeLocalHostNameDetermined(requestUri);
682+
683+
var uri = requestUri;
684+
685+
if (!requestUri.Host.Equals(s_safeLocalHostName, StringComparison.OrdinalIgnoreCase))
686+
{
687+
var url = String.Format("{0}://{1}{2}",
688+
requestUri.Scheme,
689+
requestUri.Port == 80 ? s_safeLocalHostName : s_safeLocalHostName + ":" + requestUri.Port,
690+
requestUri.PathAndQuery);
691+
uri = new Uri(url);
692+
}
693+
694+
var request = WebRequest.CreateHttp(uri);
695+
request.ServerCertificateValidationCallback += (sender, cert, chain, errors) => true;
696+
request.ServicePoint.Expect100Continue = false;
697+
request.UserAgent = "SmartStore.NET {0}".FormatInvariant(SmartStoreVersion.CurrentFullVersion);
698+
699+
return request;
700+
}
701+
702+
private static void EnsureSafeLocalHostNameDetermined(Uri requestUri)
703+
{
704+
if (s_safeLocalHostName == null)
705+
{
706+
lock (s_lock)
707+
{
708+
if (s_safeLocalHostName == null)
709+
{
710+
//var hosts = new string[]
711+
//{
712+
// requestUri.Host,
713+
// "localhost",
714+
// Dns.GetHostName(), // TODO: add local IPs also
715+
// "127.0.0.1"
716+
//};
717+
718+
//foreach (var host in hosts)
719+
//{
720+
// // ...
721+
//}
722+
s_safeLocalHostName = "localhost"; // TBD: what about ssl and differing ports?
723+
}
724+
}
725+
}
726+
}
674727
}
675728
}

src/Libraries/SmartStore.Services/Tasks/TaskScheduler.cs

Lines changed: 43 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using SmartStore.Collections;
1414
using SmartStore.Core.Infrastructure;
1515
using SmartStore.Core.Caching;
16+
using SmartStore.Core;
1617

1718
namespace SmartStore.Services.Tasks
1819
{
@@ -21,7 +22,6 @@ public class DefaultTaskScheduler : DisposableObject, ITaskScheduler, IRegistere
2122
private bool _intervalFixed;
2223
private int _sweepInterval;
2324
private string _baseUrl;
24-
private bool _mustVerifyBaseUrl;
2525
private System.Timers.Timer _timer;
2626
private bool _shuttingDown;
2727
private int _errCount;
@@ -49,7 +49,6 @@ public string BaseUrl
4949
{
5050
CheckUrl(value);
5151
_baseUrl = value.TrimEnd('/', '\\');
52-
_mustVerifyBaseUrl = true;
5352
}
5453
}
5554

@@ -137,7 +136,7 @@ public void RunSingleTask(int scheduleTaskId, IDictionary<string, string> taskPa
137136
query = qs.ToString();
138137
}
139138

140-
CallEndpoint("{0}/Execute/{1}{2}".FormatInvariant(_baseUrl, scheduleTaskId, query));
139+
CallEndpoint(new Uri("{0}/Execute/{1}{2}".FormatInvariant(_baseUrl, scheduleTaskId, query)));
141140
}
142141

143142
private void Elapsed(object sender, System.Timers.ElapsedEventArgs e)
@@ -155,7 +154,7 @@ private void Elapsed(object sender, System.Timers.ElapsedEventArgs e)
155154
_intervalFixed = true;
156155
}
157156

158-
CallEndpoint(_baseUrl + "/Sweep");
157+
CallEndpoint(new Uri(_baseUrl + "/Sweep"));
159158
}
160159
}
161160
finally
@@ -164,86 +163,76 @@ private void Elapsed(object sender, System.Timers.ElapsedEventArgs e)
164163
}
165164
}
166165

167-
protected internal virtual void CallEndpoint(string url)
166+
protected internal virtual void CallEndpoint(Uri uri)
168167
{
169168
if (_shuttingDown)
170169
return;
171170

172-
var req = (HttpWebRequest)WebRequest.Create(url);
173-
req.ServerCertificateValidationCallback += (sender, cert, chain, errors) => true;
174-
req.UserAgent = "SmartStore.NET";
171+
var req = WebHelper.CreateHttpRequestForSafeLocalCall(uri);
175172
req.Method = "POST";
176173
req.ContentType = "text/plain";
177174
req.ContentLength = 0;
178-
req.ServicePoint.Expect100Continue = false;
179175
req.Timeout = 10000; // 10 sec.
180176

181177
string authToken = CreateAuthToken();
182178
req.Headers.Add("X-AUTH-TOKEN", authToken);
183179

184-
HttpWebResponse response = null;
185-
186-
try
187-
{
188-
response = (HttpWebResponse)req.GetResponse();
189-
_errCount = 0;
190-
_mustVerifyBaseUrl = false;
191-
192-
//using (var logger = new TraceLogger())
193-
//{
194-
// logger.Warning("TaskScheduler Sweep called successfully: {0}".FormatCurrent(response.GetResponseStream().AsString()));
195-
//}
196-
}
197-
catch (Exception ex)
180+
req.GetResponseAsync().ContinueWith(t =>
198181
{
199-
HandleException(ex, url);
200-
_errCount++;
201-
if (_errCount >= 10)
182+
if (t.IsFaulted)
202183
{
203-
// 10 failed attempts in succession. Stop the timer!
204-
this.Stop();
205-
using (var logger = new TraceLogger())
184+
HandleException(t.Exception, uri);
185+
_errCount++;
186+
if (_errCount >= 10)
206187
{
207-
logger.Information("Stopping TaskScheduler sweep timer. Too many failed requests in succession.");
188+
// 10 failed attempts in succession. Stop the timer!
189+
this.Stop();
190+
using (var logger = new TraceLogger())
191+
{
192+
logger.Information("Stopping TaskScheduler sweep timer. Too many failed requests in succession.");
193+
}
208194
}
209195
}
210-
}
211-
finally
212-
{
213-
if (response != null)
196+
else
197+
{
198+
_errCount = 0;
199+
var response = t.Result;
200+
201+
//using (var logger = new TraceLogger())
202+
//{
203+
// logger.Debug("TaskScheduler Sweep called successfully: {0}".FormatCurrent(response.GetResponseStream().AsString()));
204+
//}
205+
214206
response.Dispose();
215-
}
207+
}
208+
});
216209
}
217210

218-
private void HandleException(Exception exception, string url)
211+
private void HandleException(AggregateException exception, Uri uri)
219212
{
220213
using (var logger = new TraceLogger())
221214
{
222-
string msg = "Error while calling TaskScheduler endpoint '{0}'.".FormatInvariant(url);
223-
224-
var wex = exception as WebException;
215+
string msg = "Error while calling TaskScheduler endpoint '{0}'.".FormatInvariant(uri.OriginalString);
216+
var wex = exception.InnerExceptions.OfType<WebException>().FirstOrDefault();
225217

226-
if (_mustVerifyBaseUrl)
218+
if (wex == null)
227219
{
228-
if (wex == null || wex.Response == null)
229-
{
230-
// a network related error occurred. Fallback to localhost!
231-
_baseUrl = "http://localhost:52089/taskscheduler";
232-
_mustVerifyBaseUrl = false;
233-
234-
logger.Information("A netwotk related error occurred while calling TaskScheduler endpoint'{0}'. Will try with 'localhost' on next sweep.".FormatInvariant(url));
235-
}
220+
logger.Error(msg, exception.InnerException);
236221
}
237-
238-
if (wex != null && wex.Response != null)
222+
else if (wex.Response == null)
239223
{
240-
var response = wex.Response as HttpWebResponse;
241-
msg += " HTTP {0}, {1}".FormatCurrent((int)response.StatusCode, response.StatusDescription);
242-
logger.Error(msg);
224+
logger.Error(msg, wex);
243225
}
244226
else
245227
{
246-
logger.Error(msg, exception);
228+
using (var response = wex.Response as HttpWebResponse)
229+
{
230+
if (response != null)
231+
{
232+
msg += " HTTP {0}, {1}".FormatCurrent((int)response.StatusCode, response.StatusDescription);
233+
}
234+
logger.Error(msg);
235+
}
247236
}
248237
}
249238
}

src/Presentation/SmartStore.Web/Administration/Controllers/CommonController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ public ActionResult Warnings()
523523
try
524524
{
525525
sitemapUrl = Url.RouteUrl("SitemapSEO", (object)null, _securitySettings.Value.ForceSslForAllPages ? "https" : "http");
526-
var request = (HttpWebRequest)WebRequest.Create(sitemapUrl);
526+
var request = WebHelper.CreateHttpRequestForSafeLocalCall(new Uri(sitemapUrl));
527527
request.Method = "HEAD";
528528
request.Timeout = 15000;
529529

src/Presentation/SmartStore.Web/Administration/Controllers/ThemeController.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,7 @@ private string ValidateLess(ThemeManifest manifest, int storeId)
305305
storeId,
306306
manifest.ThemeName);
307307

308-
HttpWebRequest request = WebRequest.CreateHttp(url);
309-
request.UserAgent = "SmartStore.NET {0}".FormatInvariant(SmartStoreVersion.CurrentFullVersion);
308+
var request = WebHelper.CreateHttpRequestForSafeLocalCall(new Uri(url));
310309
WebResponse response = null;
311310

312311
try

src/Presentation/SmartStore.Web/Controllers/TaskSchedulerController.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,10 @@ public ActionResult Execute(int id /* taskId */)
8383
return Content("Task '{0}' executed".FormatCurrent(task.Name));
8484
}
8585

86-
}
86+
public ContentResult Noop()
87+
{
88+
return Content("noop");
89+
}
90+
91+
}
8792
}

0 commit comments

Comments
 (0)