diff --git a/.github/workflows/monthly-copyright-update.yml b/.github/workflows/monthly-copyright-update.yml
index a45e0138..152012af 100644
--- a/.github/workflows/monthly-copyright-update.yml
+++ b/.github/workflows/monthly-copyright-update.yml
@@ -12,5 +12,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/monthly-copyright-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
+ org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
diff --git a/.github/workflows/nightly-documentation-update.yml b/.github/workflows/nightly-documentation-update.yml
index 775060f0..bb65c351 100644
--- a/.github/workflows/nightly-documentation-update.yml
+++ b/.github/workflows/nightly-documentation-update.yml
@@ -13,5 +13,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-documentation-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
+ org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
diff --git a/.github/workflows/nightly-package-update.yml b/.github/workflows/nightly-package-update.yml
index 440ba369..d1642ad1 100644
--- a/.github/workflows/nightly-package-update.yml
+++ b/.github/workflows/nightly-package-update.yml
@@ -11,5 +11,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-package-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
+ org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
diff --git a/.github/workflows/nightly-prs-to-main.yml b/.github/workflows/nightly-prs-to-main.yml
index 2ae4edd4..e02ac99f 100644
--- a/.github/workflows/nightly-prs-to-main.yml
+++ b/.github/workflows/nightly-prs-to-main.yml
@@ -12,5 +12,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-prs-to-main.yml@main
with:
repo-name: ${{ github.event.repository.name }}
+ org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
diff --git a/.github/workflows/nightly-publish-main.yml b/.github/workflows/nightly-publish-main.yml
index 4f62866b..08ad172d 100644
--- a/.github/workflows/nightly-publish-main.yml
+++ b/.github/workflows/nightly-publish-main.yml
@@ -12,6 +12,7 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-publish-main.yml@main
with:
repo-name: ${{ github.event.repository.name }}
+ org-name: ${{ github.event.repository.owner.login }}
build-platform: windows-latest
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
diff --git a/.github/workflows/nightly-submodule-update.yml b/.github/workflows/nightly-submodule-update.yml
index b2ec1118..f3c4bfb5 100644
--- a/.github/workflows/nightly-submodule-update.yml
+++ b/.github/workflows/nightly-submodule-update.yml
@@ -12,5 +12,6 @@ jobs:
uses: 51Degrees/common-ci/.github/workflows/nightly-submodule-update.yml@main
with:
repo-name: ${{ github.event.repository.name }}
+ org-name: ${{ github.event.repository.owner.login }}
secrets:
token: ${{ secrets.ACCESS_TOKEN }}
diff --git a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElement/FlowElement/JavaScriptBuilderElement.cs b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElement/FlowElement/JavaScriptBuilderElement.cs
index d129f8b9..356ceb7f 100644
--- a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElement/FlowElement/JavaScriptBuilderElement.cs
+++ b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElement/FlowElement/JavaScriptBuilderElement.cs
@@ -245,12 +245,49 @@ protected override void ManagedResourcesCleanup()
///
protected override void ProcessInternal(IFlowData data)
{
- if (data == null) throw new ArgumentNullException(nameof(data));
- SetUp(data);
+ SetUp(data, GetJSONFromData(data), GetOrAddToData(data), true);
+ }
+
+
+ ///
+ /// Default process method.
+ ///
+ ///
+ ///
+ ///
+ /// Thrown if the supplied flow data is null.
+ ///
+ public JavaScriptBuilderElementData GetFallbackResponse(IFlowData data, IJsonBuilderElementData jsonData)
+ {
+ if (jsonData == null)
+ {
+ throw new ArgumentNullException(nameof(jsonData));
+ }
+ JavaScriptBuilderElementData result = (JavaScriptBuilderElementData)CreateElementData(data.Pipeline);
+ SetUp(data, () => jsonData, () => result, false);
+ return result;
}
- private void SetUp(IFlowData data)
+ private static Func GetJSONFromData(IFlowData data) => () =>
+ {
+ try
+ {
+ return data.Get();
+ }
+ catch (KeyNotFoundException ex)
+ {
+ throw new PipelineConfigurationException(
+ Messages.ExceptionJsonBuilderNotRun, ex);
+ }
+ };
+
+ private void SetUp(
+ IFlowData data,
+ Func jsonDataProvider,
+ Func targetElementDataProvider,
+ bool throwOnGetAsFailure)
{
+ if (data == null) throw new ArgumentNullException(nameof(data));
var host = Host;
var protocol = Protocol;
bool supportsPromises = false;
@@ -276,6 +313,8 @@ private void SetUp(IFlowData data)
protocol = Constants.FALLBACK_PROTOCOL;
}
+ const string errorFormat_GetAsFailed = "Failed to get property {propertyName}";
+
// If device detection is in the Pipeline then we can check
// if the client's browser supports promises.
// This can be used to customize the JavaScript response.
@@ -292,7 +331,19 @@ private void SetUp(IFlowData data)
try
{
- var promise = data.GetAs>("Promise");
+ IAspectPropertyValue promise = null;
+ try
+ {
+ promise = data.GetAs>("Promise");
+ }
+ catch (Exception ex)
+ {
+ if (throwOnGetAsFailure)
+ {
+ throw;
+ }
+ Logger.LogError(ex, errorFormat_GetAsFailed, "Promise");
+ }
supportsPromises = promise != null && promise.HasValue && promise.Value == "Full";
}
catch (PropertyMissingException) { promisesNotAvailable(); }
@@ -317,7 +368,19 @@ private void SetUp(IFlowData data)
try
{
- var fetch = data.GetAs>("Fetch");
+ IAspectPropertyValue fetch = null;
+ try
+ {
+ fetch = data.GetAs>("Fetch");
+ }
+ catch (Exception ex)
+ {
+ if (throwOnGetAsFailure)
+ {
+ throw;
+ }
+ Logger.LogError(ex, errorFormat_GetAsFailed, "Fetch");
+ }
supportsFetch = fetch != null && fetch.HasValue && fetch.Value;
}
catch (PropertyMissingException) { fetchNotAvailable(); }
@@ -327,16 +390,8 @@ private void SetUp(IFlowData data)
}
// Get the JSON include to embed into the JavaScript include.
- string jsonObject = string.Empty;
- try
- {
- jsonObject = data.Get().Json;
- }
- catch (KeyNotFoundException ex)
- {
- throw new PipelineConfigurationException(
- Messages.ExceptionJsonBuilderNotRun, ex);
- }
+ string jsonObject = jsonDataProvider().Json;
+
var parameters = GetParameters(data);
var paramsObject = JsonConvert.SerializeObject(parameters);
@@ -380,7 +435,7 @@ private void SetUp(IFlowData data)
}
// With the gathered resources, build a new JavaScriptResource.
- BuildJavaScript(data, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, url, paramsObject);
+ BuildJavaScript(data, targetElementDataProvider, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, url, paramsObject);
}
@@ -474,6 +529,12 @@ protected virtual string GetSessionId(IFlowData data)
///
/// The instance to populate with the
/// resulting
+ /// and additional evidence source
+ ///
+ ///
+ /// The method the will inject the resulting
+ ///
+ /// into the response (even if differs from `data` above)
///
///
/// The JSON data object to include in the JavaScript.
@@ -503,6 +564,7 @@ protected virtual string GetSessionId(IFlowData data)
///
protected void BuildJavaScript(
IFlowData data,
+ Func targetElementDataProvider,
string jsonObject,
string sessionId,
int sequence,
@@ -511,7 +573,15 @@ protected void BuildJavaScript(
string url,
string parameters)
{
- BuildJavaScript(data, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, new Uri(url), parameters);
+ BuildJavaScript(data, targetElementDataProvider, jsonObject, sessionId, sequence, supportsPromises, supportsFetch, new Uri(url), parameters);
+ }
+
+ private Func GetOrAddToData(IFlowData data)
+ {
+ return () => (JavaScriptBuilderElementData)
+ data.GetOrAdd(
+ ElementDataKeyTyped,
+ CreateElementData);
}
///
@@ -521,6 +591,12 @@ protected void BuildJavaScript(
///
/// The instance to populate with the
/// resulting
+ /// and additional evidence source
+ ///
+ ///
+ /// The method the will inject the resulting
+ ///
+ /// into the response (even if differs from `data` above)
///
///
/// The JSON data object to include in the JavaScript.
@@ -549,7 +625,8 @@ protected void BuildJavaScript(
/// Thrown if the supplied flow data is null.
///
protected void BuildJavaScript(
- IFlowData data,
+ IFlowData data,
+ Func targetElementDataProvider,
string jsonObject,
string sessionId,
int sequence,
@@ -558,12 +635,9 @@ protected void BuildJavaScript(
Uri url,
string parameters)
{
- if (data == null) throw new ArgumentNullException(nameof(data));
-
- JavaScriptBuilderElementData elementData = (JavaScriptBuilderElementData)
- data.GetOrAdd(
- ElementDataKeyTyped,
- CreateElementData);
+ if (data == null) throw new ArgumentNullException(nameof(data));
+
+ JavaScriptBuilderElementData elementData = targetElementDataProvider();
string objectName = ObjName;
// Try and get the requested object name from evidence.
diff --git a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElementTests/JavaScriptBuilderElementTests.cs b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElementTests/JavaScriptBuilderElementTests.cs
index 44d78872..66ede0b3 100644
--- a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElementTests/JavaScriptBuilderElementTests.cs
+++ b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JavaScriptBuilderElementTests/JavaScriptBuilderElementTests.cs
@@ -196,6 +196,34 @@ public void JavaScriptBuilder_VerifySession()
$"JavaScript does not contain expected sequence '1'.");
}
+ ///
+ /// Check that the callback URL is generated correctly.
+ ///
+ [TestMethod]
+ public void JavaScriptBuilder_VerifyFallbackResponse()
+ {
+ _javaScriptBuilderElement =
+ new JavaScriptBuilderElementBuilder(_loggerFactory)
+ .SetEndpoint("/json")
+ .Build();
+
+ var flowData = new Mock();
+
+ flowData.Setup(d => d.Get())
+ .Throws();
+ var evidence = new Evidence(_loggerFactory.CreateLogger());
+ flowData.Setup(d => d.GetEvidence())
+ .Returns(evidence);
+
+ var jsonData = new Mock();
+ jsonData.Setup(j => j.Json)
+ .Returns("{}");
+
+ IJavaScriptBuilderElementData result = _javaScriptBuilderElement.GetFallbackResponse(flowData.Object, jsonData.Object);
+
+ Assert.IsFalse(string.IsNullOrWhiteSpace(result.JavaScript));
+ }
+
///
/// Check that the callback URL is generated correctly.
///
diff --git a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElement/FlowElement/JsonBuilderElement.cs b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElement/FlowElement/JsonBuilderElement.cs
index fc34e3e0..a74f0ec5 100644
--- a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElement/FlowElement/JsonBuilderElement.cs
+++ b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElement/FlowElement/JsonBuilderElement.cs
@@ -215,7 +215,31 @@ protected override void ManagedResourcesCleanup()
///
/// Thrown if the supplied flow data is null.
///
- protected override void ProcessInternal(IFlowData data)
+ protected override void ProcessInternal(IFlowData data) =>
+ BuildAndInjectJSON(
+ data,
+ data.GetOrAdd(
+ ElementDataKeyTyped,
+ CreateElementData),
+ true);
+
+ ///
+ /// Transform the data in the flow data instance into a
+ /// JSON object.
+ ///
+ ///
+ /// The
+ ///
+ ///
+ /// The
+ ///
+ ///
+ /// Whether to throw if sequence number was not found
+ ///
+ ///
+ /// Thrown if the supplied flow data is null.
+ ///
+ private void BuildAndInjectJSON(IFlowData data, IJsonBuilderElementData elementData, bool requireSequenceNumber)
{
if (data == null) throw new ArgumentNullException(nameof(data));
@@ -225,24 +249,51 @@ protected override void ProcessInternal(IFlowData data)
config = _pipelineConfigs.GetOrAdd(data.Pipeline, config);
}
- var elementData = data.GetOrAdd(
- ElementDataKeyTyped,
- CreateElementData);
- var jsonString = BuildJson(data, config);
+ var jsonString = BuildJson(data, config, requireSequenceNumber);
elementData.Json = jsonString;
}
+ ///
+ /// Transform the data in the flow data instance into a
+ /// JSON object.
+ ///
+ ///
+ /// The
+ ///
+ ///
+ /// Thrown if the supplied flow data is null.
+ ///
+ public IJsonBuilderElementData GetFallbackResponse(IFlowData data)
+ {
+ var elementData = CreateElementData(data.Pipeline);
+ BuildAndInjectJSON(data, elementData, false);
+ return elementData;
+ }
+
///
/// Create and populate a JSON string from the specified data.
///
///
/// The configuration to use
+ /// The configuration to use
///
/// A string containing the data in JSON format.
///
- protected virtual string BuildJson(IFlowData data, PipelineConfig config)
+ protected virtual string BuildJson(IFlowData data, PipelineConfig config, bool requireSequenceNumber)
{
- int sequenceNumber = GetSequenceNumber(data);
+ int? sequenceNumber = null;
+ try
+ {
+ sequenceNumber = GetSequenceNumber(data);
+ }
+ catch (PipelineException e)
+ {
+ if (requireSequenceNumber)
+ {
+ throw;
+ }
+ Logger.LogError(e, $"Failed to get {nameof(sequenceNumber)}.");
+ }
// Get property values from all the elements and add the ones that
// are accessible to a dictionary.
@@ -250,7 +301,7 @@ protected virtual string BuildJson(IFlowData data, PipelineConfig config)
// Only populate the JavaScript properties if the sequence
// has not reached max iterations.
- if (sequenceNumber < Constants.MAX_JAVASCRIPT_ITERATIONS)
+ if (!sequenceNumber.HasValue || sequenceNumber.Value < Constants.MAX_JAVASCRIPT_ITERATIONS)
{
AddJavaScriptProperties(data, allProperties);
}
diff --git a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElementTests/JsonBuilderElementTests.cs b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElementTests/JsonBuilderElementTests.cs
index 8ba47e3d..58de5c52 100644
--- a/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElementTests/JsonBuilderElementTests.cs
+++ b/FiftyOne.Pipeline.Elements/FiftyOne.Pipeline.JsonBuilderElementTests/JsonBuilderElementTests.cs
@@ -98,6 +98,17 @@ public void JsonBuilder_ValidJson()
Assert.IsTrue(IsExpectedJson(json));
}
+ ///
+ /// Check that the JSON produced by the JsonBuilder is valid.
+ ///
+ [TestMethod]
+ public void JsonBuilder_NonEmptyFallback()
+ {
+ var json = TestIteration(1, null, null, (e, fd) => ((JsonBuilderElement)e).GetFallbackResponse(fd).Json);
+
+ Assert.IsFalse(string.IsNullOrWhiteSpace(json));
+ }
+
///
/// Check that the JSON element removes JavaScript properties from the
/// response after max number of iterations has been reached.
@@ -731,7 +742,8 @@ public class JsonBuilder
private string TestIteration(int iteration,
Dictionary data = null,
- Mock flowData = null)
+ Mock flowData = null,
+ Func processFunc = null)
{
if(data == null)
{
@@ -765,6 +777,11 @@ private string TestIteration(int iteration,
});
flowData.Setup(d => d.Pipeline).Returns(_pipeline.Object);
+ if (processFunc != null)
+ {
+ return processFunc(_jsonBuilderElement, flowData.Object);
+ }
+
_jsonBuilderElement.Process(flowData.Object);
var json = result["json"].ToString();
diff --git a/FiftyOne.Pipeline.Web.Shared/Services/ClientsidePropertyService.cs b/FiftyOne.Pipeline.Web.Shared/Services/ClientsidePropertyService.cs
index 2e21407e..12911648 100644
--- a/FiftyOne.Pipeline.Web.Shared/Services/ClientsidePropertyService.cs
+++ b/FiftyOne.Pipeline.Web.Shared/Services/ClientsidePropertyService.cs
@@ -35,6 +35,8 @@
using System.Text;
using FiftyOne.Pipeline.Web.Shared.Adapters;
using Microsoft.Extensions.Logging;
+using FiftyOne.Pipeline.JavaScriptBuilder.Data;
+using FiftyOne.Pipeline.JsonBuilder.Data;
namespace FiftyOne.Pipeline.Web.Shared.Services
{
@@ -48,15 +50,43 @@ public class ClientsidePropertyService : IClientsidePropertyService
///
/// Pipeline
///
- private IPipeline _pipeline;
+ private readonly IPipeline _pipeline;
- private ILogger _logger;
+ private readonly ILogger _logger;
///
/// A list of all the HTTP headers that are requested evidence
/// for elements that populate JavaScript properties
///
- private StringValues _headersAffectingJavaScript;
+ private StringValues? _headersAffectingJavaScript = null;
+ private readonly object _headersAffectingJavaScriptLock = new object();
+
+ private StringValues HeadersAffectingJavaScript
+ {
+ get
+ {
+ if (_headersAffectingJavaScript.HasValue)
+ {
+ return _headersAffectingJavaScript.Value;
+ }
+
+ lock (_headersAffectingJavaScriptLock)
+ {
+ if (_headersAffectingJavaScript.HasValue)
+ {
+ return _headersAffectingJavaScript.Value;
+ }
+
+ CollectHeadersAffectingJavaScript(out StringValues newHeaders, out bool gotExceptions);
+
+ if (!gotExceptions)
+ {
+ _headersAffectingJavaScript = newHeaders;
+ }
+ return newHeaders;
+ }
+ }
+ }
private enum ContentType
{
@@ -68,7 +98,7 @@ private enum ContentType
/// The cache control values that will be set for the JavaScript and
/// JSON.
///
- private StringValues _cacheControl = new StringValues(
+ private readonly StringValues _cacheControl = new StringValues(
new string[] {
"private",
"max-age=1800",
@@ -90,11 +120,27 @@ public ClientsidePropertyService(
_pipeline = pipeline;
_logger = logger;
+ }
- var headersAffectingJavaScript = new List();
+ private void CollectHeadersAffectingJavaScript(out StringValues headers, out bool gotExceptions)
+ {
+ var headersAffectingJavaScript = new List();
+ gotExceptions = false;
+
+ foreach (var flowElement in _pipeline.FlowElements)
+ {
+ IEvidenceKeyFilter filter;
+ try
+ {
+ filter = flowElement.EvidenceKeyFilter;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"Failed to get {nameof(flowElement.EvidenceKeyFilter)} from {{flowElementType}}", flowElement.GetType().Name);
+ gotExceptions = true;
+ continue;
+ }
- foreach (var filter in _pipeline.FlowElements.Select(e => e.EvidenceKeyFilter))
- {
// If the filter is a white list or derived type then
// get all HTTP header evidence keys from white list
// and add them to the headers that could affect the
@@ -120,7 +166,7 @@ public ClientsidePropertyService(
.Distinct(StringComparer.OrdinalIgnoreCase));
}
}
- _headersAffectingJavaScript = new StringValues(headersAffectingJavaScript.ToArray());
+ headers = new StringValues(headersAffectingJavaScript.ToArray());
}
///
@@ -167,10 +213,27 @@ private void ServeContent(IContextAdapter context, IFlowData flowData, ContentTy
context.Response.Clear();
context.Response.ClearHeaders();
- // Get the hash code.
- var hash = flowData.GenerateKey(_pipeline.EvidenceKeyFilter).GetHashCode();
+ bool hadFailures = false;
+
+ IEvidenceKeyFilter pipelineEvidenceKeyFilter = null;
+ try
+ {
+ pipelineEvidenceKeyFilter = _pipeline.EvidenceKeyFilter;
+ }
+ catch (PipelineException ex)
+ {
+ _logger?.LogError(ex, $"Failed to get {nameof(_pipeline.EvidenceKeyFilter)} from {nameof(_pipeline)}");
+ hadFailures = true;
+ }
+
+ // Get the hash code.
+ int? hash = null;
+ if (pipelineEvidenceKeyFilter != null) {
+ hash = flowData.GenerateKey(pipelineEvidenceKeyFilter).GetHashCode();
+ }
- if (int.TryParse(context.Request.GetHeaderValue("If-None-Match"),
+ if (hash.HasValue &&
+ int.TryParse(context.Request.GetHeaderValue("If-None-Match"),
out int previousHash) &&
hash == previousHash)
{
@@ -181,27 +244,57 @@ private void ServeContent(IContextAdapter context, IFlowData flowData, ContentTy
{
// Otherwise, return the requested content to the client.
string content = null;
+ Func GetJsonData = () =>
+ {
+ var jsonElement = flowData.Pipeline.GetElement();
+ if (jsonElement == null)
+ {
+ throw new PipelineConfigurationException(
+ Messages.ExceptionNoJsonBuilder);
+ }
+ IJsonBuilderElementData jsonData = null;
+ try
+ {
+ jsonData = flowData.GetFromElement(jsonElement);
+ }
+ catch (PipelineException ex)
+ {
+ _logger?.LogError(ex, "Failed to get data from {flowElementType}", jsonElement.GetType().Name);
+ jsonData = jsonElement.GetFallbackResponse(flowData);
+ hadFailures = true;
+ }
+ return jsonData;
+ };
+
+ Func GetJsData = () =>
+ {
+ var jsElement = flowData.Pipeline.GetElement();
+ if (jsElement == null)
+ {
+ throw new PipelineConfigurationException(
+ Messages.ExceptionNoJavaScriptBuilder);
+ }
+ IJavaScriptBuilderElementData jsData;
+ try
+ {
+ jsData = flowData.GetFromElement(jsElement);
+ }
+ catch (PipelineException ex)
+ {
+ _logger?.LogError(ex, "Failed to get data from {flowElementType}", jsElement.GetType().Name);
+ jsData = jsElement.GetFallbackResponse(flowData, GetJsonData());
+ hadFailures = true;
+ }
+ return jsData;
+ };
+
switch (contentType)
{
case ContentType.JavaScript:
- var jsElement = flowData.Pipeline.GetElement();
- if (jsElement == null)
- {
- throw new PipelineConfigurationException(
- Messages.ExceptionNoJavaScriptBuilder);
- }
- var jsData = flowData.GetFromElement(jsElement);
- content = jsData?.JavaScript;
+ content = GetJsData()?.JavaScript;
break;
case ContentType.Json:
- var jsonElement = flowData.Pipeline.GetElement();
- if (jsonElement == null)
- {
- throw new PipelineConfigurationException(
- Messages.ExceptionNoJsonBuilder);
- }
- var jsonData = flowData.GetFromElement(jsonElement);
- content = jsonData?.Json;
+ content = GetJsonData()?.Json;
break;
default:
break;
@@ -215,9 +308,10 @@ private void ServeContent(IContextAdapter context, IFlowData flowData, ContentTy
context.Response.StatusCode = 200;
SetHeaders(context,
- hash.ToString(CultureInfo.InvariantCulture),
+ hash.HasValue ? hash.Value.ToString(CultureInfo.InvariantCulture) : null,
length,
- contentType == ContentType.JavaScript ? "x-javascript" : "json");
+ contentType == ContentType.JavaScript ? "x-javascript" : "json",
+ !hadFailures);
context.Response.Write(content);
}
@@ -231,7 +325,8 @@ private void ServeContent(IContextAdapter context, IFlowData flowData, ContentTy
///
///
///
- private void SetHeaders(IContextAdapter context, string hash, int contentLength, string contentType)
+ ///
+ private void SetHeaders(IContextAdapter context, string hash, int contentLength, string contentType, bool shouldCache)
{
try
{
@@ -239,15 +334,19 @@ private void SetHeaders(IContextAdapter context, string hash, int contentLength,
$"application/{contentType}");
context.Response.SetHeader("Content-Length",
contentLength.ToString(CultureInfo.InvariantCulture));
- context.Response.SetHeader("Cache-Control", _cacheControl);
- if (string.IsNullOrEmpty(_headersAffectingJavaScript.ToString()) == false)
+ context.Response.SetHeader("Cache-Control", shouldCache ? _cacheControl.ToString() : "no-cache");
+ var headersAffectingJavaScript = HeadersAffectingJavaScript;
+ if (string.IsNullOrEmpty(headersAffectingJavaScript.ToString()) == false)
{
- context.Response.SetHeader("Vary", _headersAffectingJavaScript);
+ context.Response.SetHeader("Vary", headersAffectingJavaScript);
+ }
+ if (!string.IsNullOrEmpty(hash))
+ {
+ context.Response.SetHeader("ETag", new StringValues(
+ new string[] {
+ hash,
+ }));
}
- context.Response.SetHeader("ETag", new StringValues(
- new string[] {
- hash,
- }));
var origin = GetAllowOrigin(context.Request);
if (origin != null)
{
diff --git a/Web Integration/Tests/FiftyOne.Pipeline.Web.Shared.Tests/ClientsidePropertyServiceTests.cs b/Web Integration/Tests/FiftyOne.Pipeline.Web.Shared.Tests/ClientsidePropertyServiceTests.cs
index 05e8bba4..f15d1118 100644
--- a/Web Integration/Tests/FiftyOne.Pipeline.Web.Shared.Tests/ClientsidePropertyServiceTests.cs
+++ b/Web Integration/Tests/FiftyOne.Pipeline.Web.Shared.Tests/ClientsidePropertyServiceTests.cs
@@ -437,6 +437,8 @@ private void Configure(List flowElements = null)
}
_pipeline.Setup(p => p.FlowElements)
.Returns(flowElements);
+ _pipeline.Setup(p => p.EvidenceKeyFilter)
+ .Returns(new EvidenceKeyFilterWhitelist(new List()));
// Configure the key for this flow data to contain a fake value
// that we can use to test the cached response handling.
_defaultDataKey = new DataKeyBuilder().Add(1, "test", "value").Build();