diff --git a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs index cd15335e57..b541182de0 100644 --- a/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs +++ b/src/Umbraco.Tests/Scheduling/BackgroundTaskRunnerTests.cs @@ -749,7 +749,7 @@ namespace Umbraco.Tests.Scheduling HasRun = true; } - public override Task PerformRunAsync() + public override Task PerformRunAsync(CancellationToken token) { throw new NotImplementedException(); } @@ -833,7 +833,7 @@ namespace Umbraco.Tests.Scheduling Thread.Sleep(_runMilliseconds); } - public override Task PerformRunAsync() + public override Task PerformRunAsync(CancellationToken token) { throw new NotImplementedException(); } diff --git a/src/Umbraco.Web/Mvc/AdminTokenAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/AdminTokenAuthorizeAttribute.cs index cbd2e0e519..dc8aa15f6a 100644 --- a/src/Umbraco.Web/Mvc/AdminTokenAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Mvc/AdminTokenAuthorizeAttribute.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Net.Http.Headers; using System.Text; using System.Text.RegularExpressions; using System.Web; @@ -36,22 +37,33 @@ namespace Umbraco.Web.Mvc return _applicationContext ?? ApplicationContext.Current; } + public const string AuthorizationType = "AToken"; + /// - /// Used to return the value that needs to go in the Authorization header + /// Used to return the full value that needs to go in the Authorization header /// /// /// public static string GetAuthHeaderTokenVal(ApplicationContext appContext) { - var admin = appContext.Services.UserService.GetUserById(0); + return string.Format("{0} {1}", AuthorizationType, GetAuthHeaderVal(appContext)); + } + public static AuthenticationHeaderValue GetAuthenticationHeaderValue(ApplicationContext appContext) + { + return new AuthenticationHeaderValue(AuthorizationType, GetAuthHeaderVal(appContext)); + } + + private static string GetAuthHeaderVal(ApplicationContext appContext) + { + var admin = appContext.Services.UserService.GetUserById(0); var token = string.Format("{0}u____u{1}u____u{2}", admin.Email, admin.Username, admin.RawPasswordValue); var encrypted = token.EncryptWithMachineKey(); var bytes = Encoding.UTF8.GetBytes(encrypted); var base64 = Convert.ToBase64String(bytes); - return "AToken val=\"" + base64 + "\""; + return string.Format("val=\"{0}\"", base64); } /// diff --git a/src/Umbraco.Web/Scheduling/LogScrubber.cs b/src/Umbraco.Web/Scheduling/LogScrubber.cs index d6c096bf74..14f534653d 100644 --- a/src/Umbraco.Web/Scheduling/LogScrubber.cs +++ b/src/Umbraco.Web/Scheduling/LogScrubber.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using System.Web; using System.Web.Caching; @@ -74,7 +75,7 @@ namespace Umbraco.Web.Scheduling } } - public override Task PerformRunAsync() + public override Task PerformRunAsync(CancellationToken token) { throw new NotImplementedException(); } diff --git a/src/Umbraco.Web/Scheduling/RecurringTaskBase.cs b/src/Umbraco.Web/Scheduling/RecurringTaskBase.cs index d710a70e03..dc82795852 100644 --- a/src/Umbraco.Web/Scheduling/RecurringTaskBase.cs +++ b/src/Umbraco.Web/Scheduling/RecurringTaskBase.cs @@ -55,7 +55,7 @@ namespace Umbraco.Web.Scheduling /// Classes inheriting from RecurringTaskBase must implement PerformRun. public virtual async Task RunAsync(CancellationToken token) { - await PerformRunAsync(); + await PerformRunAsync(token); Repeat(); } @@ -95,8 +95,9 @@ namespace Umbraco.Web.Scheduling /// /// Runs the task asynchronously. /// + /// A cancellation token. /// A instance representing the execution of the background task. - public abstract Task PerformRunAsync(); + public abstract Task PerformRunAsync(CancellationToken token); /// /// Gets a new occurence of the recurring task. diff --git a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs index 9db21fba8a..0f7cb8c205 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledPublishing.cs @@ -1,12 +1,10 @@ using System; -using System.Diagnostics; -using System.Net; -using System.Text; +using System.Net.Http; +using System.Threading; using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; -using Umbraco.Core.Publishing; using Umbraco.Core.Sync; using Umbraco.Web.Mvc; @@ -41,6 +39,12 @@ namespace Umbraco.Web.Scheduling public override void PerformRun() { + throw new NotImplementedException(); + } + + public override async Task PerformRunAsync(CancellationToken token) + { + if (_appContext == null) return; if (ServerEnvironmentHelper.GetStatus(_settings) == CurrentServerEnvironmentStatus.Slave) { @@ -57,7 +61,7 @@ namespace Umbraco.Web.Scheduling var umbracoBaseUrl = ServerEnvironmentHelper.GetCurrentServerUmbracoBaseUrl(_appContext, _settings); try - { + { if (string.IsNullOrWhiteSpace(umbracoBaseUrl)) { @@ -66,13 +70,26 @@ namespace Umbraco.Web.Scheduling else { var url = string.Format("{0}RestServices/ScheduledPublish/Index", umbracoBaseUrl.EnsureEndsWith('/')); - using (var wc = new WebClient()) + using (var wc = new HttpClient()) { + var request = new HttpRequestMessage() + { + RequestUri = new Uri(url), + Method = HttpMethod.Post, + Content = new StringContent(string.Empty) + }; //pass custom the authorization header - wc.Headers.Set("Authorization", AdminTokenAuthorizeAttribute.GetAuthHeaderTokenVal(_appContext)); + request.Headers.Authorization = AdminTokenAuthorizeAttribute.GetAuthenticationHeaderValue(_appContext); - var result = wc.UploadString(url, ""); - } + try + { + var result = await wc.SendAsync(request, token); + } + catch (Exception ex) + { + LogHelper.Error("An error occurred calling scheduled publish url", ex); + } + } } } catch (Exception ee) @@ -88,14 +105,9 @@ namespace Umbraco.Web.Scheduling } } - public override Task PerformRunAsync() - { - throw new NotImplementedException(); - } - public override bool IsAsync { - get { return false; } + get { return true; } } public override bool RunsOnShutdown diff --git a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs index cba3cb4fc8..1015b2d4f6 100644 --- a/src/Umbraco.Web/Scheduling/ScheduledTasks.cs +++ b/src/Umbraco.Web/Scheduling/ScheduledTasks.cs @@ -1,15 +1,13 @@ using System; using System.Collections; -using System.Linq; using System.Net; +using System.Net.Http; +using System.Threading; using System.Threading.Tasks; -using System.Xml; -using Umbraco.Core.Configuration; +using Umbraco.Core; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Logging; -using Umbraco.Core.Publishing; using Umbraco.Core.Sync; -using Umbraco.Core; namespace Umbraco.Web.Scheduling { @@ -44,18 +42,19 @@ namespace Umbraco.Web.Scheduling return new ScheduledTasks(this); } - private void ProcessTasks() + private async Task ProcessTasksAsync(CancellationToken token) { var scheduledTasks = _settings.ScheduledTasks.Tasks; foreach (var t in scheduledTasks) { var runTask = false; - if (!ScheduledTaskTimes.ContainsKey(t.Alias)) + if (ScheduledTaskTimes.ContainsKey(t.Alias) == false) { runTask = true; ScheduledTaskTimes.Add(t.Alias, DateTime.Now); } - /// Add 1 second to timespan to compensate for differencies in timer + + // Add 1 second to timespan to compensate for differencies in timer else if ( new TimeSpan( DateTime.Now.Ticks - ((DateTime)ScheduledTaskTimes[t.Alias]).Ticks).TotalSeconds + 1 >= t.Interval) @@ -66,33 +65,46 @@ namespace Umbraco.Web.Scheduling if (runTask) { - bool taskResult = GetTaskByHttp(t.Url); + var taskResult = await GetTaskByHttpAync(t.Url, token); if (t.Log) LogHelper.Info(string.Format("{0} has been called with response: {1}", t.Alias, taskResult)); } } } - private bool GetTaskByHttp(string url) + private async Task GetTaskByHttpAync(string url, CancellationToken token) { - var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url); - - try + using (var wc = new HttpClient()) { - using (var response = (HttpWebResponse)myHttpWebRequest.GetResponse()) + var request = new HttpRequestMessage() { - return response.StatusCode == HttpStatusCode.OK; - } - } - catch (Exception ex) - { - LogHelper.Error("An error occurred calling web task for url: " + url, ex); - } + RequestUri = new Uri(url), + Method = HttpMethod.Get, + Content = new StringContent(string.Empty) + }; - return false; + //TODO: pass custom the authorization header, currently these aren't really secured! + //request.Headers.Authorization = AdminTokenAuthorizeAttribute.GetAuthenticationHeaderValue(_appContext); + + try + { + var result = await wc.SendAsync(request, token); + return result.StatusCode == HttpStatusCode.OK; + } + catch (Exception ex) + { + LogHelper.Error("An error occurred calling web task for url: " + url, ex); + } + return false; + } } public override void PerformRun() + { + throw new NotImplementedException(); + } + + public override async Task PerformRunAsync(CancellationToken token) { if (ServerEnvironmentHelper.GetStatus(_settings) == CurrentServerEnvironmentStatus.Slave) { @@ -108,7 +120,7 @@ namespace Umbraco.Web.Scheduling try { - ProcessTasks(); + await ProcessTasksAsync(token); } catch (Exception ee) { @@ -121,14 +133,9 @@ namespace Umbraco.Web.Scheduling } } - public override Task PerformRunAsync() - { - throw new NotImplementedException(); - } - public override bool IsAsync { - get { return false; } + get { return true; } } public override bool RunsOnShutdown diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index e32fdc3a83..cd85e82686 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -562,21 +562,26 @@ namespace Umbraco.Web var httpContext = ((HttpApplication)sender).Context; LogHelper.Debug("Begin request: {0}.", () => httpContext.Request.Url); BeginRequest(new HttpContextWrapper(httpContext)); - - //disable asp.net headers (security) - try - { - httpContext.Response.Headers.Remove("Server"); - //this doesn't normally work since IIS sets it but we'll keep it here anyways. - httpContext.Response.Headers.Remove("X-Powered-By"); - } - catch (PlatformNotSupportedException ex) - { - // can't remove headers this way on IIS6 or cassini. - } - }; + //disable asp.net headers (security) + // This is the correct place to modify headers according to MS: + // https://our.umbraco.org/forum/umbraco-7/using-umbraco-7/65241-Heap-error-from-header-manipulation?p=0#comment220889 + app.PostReleaseRequestState += (sender, args) => + { + var httpContext = ((HttpApplication)sender).Context; + try + { + httpContext.Response.Headers.Remove("Server"); + //this doesn't normally work since IIS sets it but we'll keep it here anyways. + httpContext.Response.Headers.Remove("X-Powered-By"); + } + catch (PlatformNotSupportedException ex) + { + // can't remove headers this way on IIS6 or cassini. + } + }; + app.PostResolveRequestCache += (sender, e) => { var httpContext = ((HttpApplication)sender).Context;