diff --git a/RMuseum/Controllers/ArtifactController.cs b/RMuseum/Controllers/ArtifactController.cs
index f68f72b5..4468c089 100644
--- a/RMuseum/Controllers/ArtifactController.cs
+++ b/RMuseum/Controllers/ArtifactController.cs
@@ -30,6 +30,17 @@ namespace RMuseum.Controllers
[Route("api/artifacts")]
public class ArtifactController : Controller
{
+ ///
+ /// HTTP dates only have one-second precision - truncate before using a value for
+ /// Last-Modified/If-Modified-Since comparisons, or a DB value with sub-second precision
+ /// would always fail the >= comparison against a client's necessarily-truncated header
+ ///
+ ///
+ ///
+ private static DateTime TruncateToSeconds(DateTime dt)
+ {
+ return new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Kind);
+ }
///
/// gets specified publish artifact item info (including images + attributes)
///
@@ -51,12 +62,12 @@ namespace RMuseum.Controllers
if (itemInfo.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = itemInfo.Result.Item.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.Item.LastModified);
Response.Headers.CacheControl = "public,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.Item.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.Item.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -92,12 +103,12 @@ namespace RMuseum.Controllers
if (itemsInfo.Result.Items.Count() > 0)
{
DateTime lastModification = itemsInfo.Result.Items.Max(i => i.LastModified);
- Response.GetTypedHeaders().LastModified = lastModification;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(lastModification);
Response.Headers.CacheControl = "public,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= lastModification)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(lastModification))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -185,12 +196,12 @@ namespace RMuseum.Controllers
if (itemsInfo.Result.Items.Count() > 0)
{
DateTime lastModification = itemsInfo.Result.Items.Max(i => i.LastModified);
- Response.GetTypedHeaders().LastModified = lastModification;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(lastModification);
Response.Headers.CacheControl = "private,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= lastModification)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(lastModification))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -217,12 +228,12 @@ namespace RMuseum.Controllers
if (itemsInfo.Result.Length > 0)
{
DateTime lastModification = itemsInfo.Result.Max(i => i.LastModified);
- Response.GetTypedHeaders().LastModified = lastModification;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(lastModification);
Response.Headers.CacheControl = "public,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= lastModification)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(lastModification))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -259,12 +270,12 @@ namespace RMuseum.Controllers
}
- Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.LastModified);
Response.Headers.CacheControl = "public,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -300,12 +311,12 @@ namespace RMuseum.Controllers
}
- Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.LastModified);
Response.Headers.CacheControl = "public,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -402,12 +413,12 @@ namespace RMuseum.Controllers
_memoryCache.Set(cacheKey, itemInfo, TimeSpan.FromHours(1));
}
- Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.LastModified);
Response.Headers.CacheControl = "public,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -464,12 +475,12 @@ namespace RMuseum.Controllers
if (itemInfo.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.LastModified);
Response.Headers.CacheControl = "private,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -528,12 +539,12 @@ namespace RMuseum.Controllers
if (itemInfo.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.LastModified);
Response.Headers.CacheControl = "private,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -592,12 +603,12 @@ namespace RMuseum.Controllers
if (itemInfo.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.LastModified);
Response.Headers.CacheControl = "private,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -723,12 +734,12 @@ namespace RMuseum.Controllers
}
DateTime lastModification = lastModified.Result;
- Response.GetTypedHeaders().LastModified = lastModification;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(lastModification);
Response.Headers.CacheControl = "public,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= lastModification)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(lastModification))
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -1161,12 +1172,12 @@ namespace RMuseum.Controllers
if (itemInfo.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = itemInfo.Result.Item.LastModified;
+ Response.GetTypedHeaders().LastModified = TruncateToSeconds(itemInfo.Result.Item.LastModified);
Response.Headers.CacheControl = "private,max-age=300";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= itemInfo.Result.Item.LastModified)
+ requestHeaders.IfModifiedSince.Value >= TruncateToSeconds(itemInfo.Result.Item.LastModified))
{
return StatusCode(StatusCodes.Status304NotModified);
}
diff --git a/RMuseum/Controllers/GanjoorController.cs b/RMuseum/Controllers/GanjoorController.cs
index 0fcf06fe..fb25aa9a 100644
--- a/RMuseum/Controllers/GanjoorController.cs
+++ b/RMuseum/Controllers/GanjoorController.cs
@@ -323,6 +323,7 @@ namespace RMuseum.Controllers
return NotFound();
lastModified = img.Result.LastModified;
+ lastModified = new DateTime(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, lastModified.Kind);
diff --git a/RMuseum/Controllers/ImageController.cs b/RMuseum/Controllers/ImageController.cs
index c6bc2d27..29fb767c 100644
--- a/RMuseum/Controllers/ImageController.cs
+++ b/RMuseum/Controllers/ImageController.cs
@@ -51,12 +51,14 @@ namespace RMuseum.Controllers
}
- Response.GetTypedHeaders().LastModified = img.Result.LastModified;
+ DateTime lastModified = img.Result.LastModified;
+ lastModified = new DateTime(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, lastModified.Kind);
+ Response.GetTypedHeaders().LastModified = lastModified;
Response.Headers.CacheControl = "public,max-age=86400";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= img.Result.LastModified)
+ requestHeaders.IfModifiedSince.Value >= lastModified)
{
return StatusCode(StatusCodes.Status304NotModified);
}
diff --git a/RMuseum/Controllers/RecitationController.cs b/RMuseum/Controllers/RecitationController.cs
index afa2ef97..074fc304 100644
--- a/RMuseum/Controllers/RecitationController.cs
+++ b/RMuseum/Controllers/RecitationController.cs
@@ -179,13 +179,15 @@ namespace RMuseum.Controllers
if (narration.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated
+ DateTime lastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated
+ lastModified = new DateTime(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, lastModified.Kind);
+ Response.GetTypedHeaders().LastModified = lastModified;
Response.Headers.CacheControl = "public,max-age=86400";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= narration.Result.UploadDate)
+ requestHeaders.IfModifiedSince.Value >= lastModified)
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -222,12 +224,14 @@ namespace RMuseum.Controllers
if (narration.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated
+ DateTime lastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated
+ lastModified = new DateTime(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, lastModified.Kind);
+ Response.GetTypedHeaders().LastModified = lastModified;
Response.Headers.CacheControl = "public,max-age=86400";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= narration.Result.UploadDate)
+ requestHeaders.IfModifiedSince.Value >= lastModified)
{
return StatusCode(StatusCodes.Status304NotModified);
}
@@ -259,12 +263,14 @@ namespace RMuseum.Controllers
if (narration.Result == null)
return NotFound();
- Response.GetTypedHeaders().LastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated
+ DateTime lastModified = narration.Result.UploadDate;//TODO: Add a FileLastUpdated field to narrations to indicate the last time the mp3/xml files have been updated
+ lastModified = new DateTime(lastModified.Year, lastModified.Month, lastModified.Day, lastModified.Hour, lastModified.Minute, lastModified.Second, lastModified.Kind);
+ Response.GetTypedHeaders().LastModified = lastModified;
Response.Headers.CacheControl = "public,max-age=86400";
var requestHeaders = Request.GetTypedHeaders();
if (requestHeaders.IfModifiedSince.HasValue &&
- requestHeaders.IfModifiedSince.Value >= narration.Result.UploadDate)
+ requestHeaders.IfModifiedSince.Value >= lastModified)
{
return StatusCode(StatusCodes.Status304NotModified);
}
diff --git a/RMuseum/RMuseum.xml b/RMuseum/RMuseum.xml
index 266b2ab4..73a10c21 100644
--- a/RMuseum/RMuseum.xml
+++ b/RMuseum/RMuseum.xml
@@ -41,6 +41,15 @@
+
+
+ HTTP dates only have one-second precision - truncate before using a value for
+ Last-Modified/If-Modified-Since comparisons, or a DB value with sub-second precision
+ would always fail the >= comparison against a client's necessarily-truncated header
+
+
+
+
gets specified publish artifact item info (including images + attributes)
@@ -20761,11 +20770,25 @@
-
+
+
+ extracts the searchable part of a poem title, discarding pure boilerplate like
+ "غزل شمارهٔ ۱" or "بخش ۴۷" which carries no information beyond the ordinal number,
+ while keeping either the whole title (if it has no number at all, e.g. "طهمورث")
+ or just the descriptive part after the number (e.g. "بخش ۴۷ - تشبیه کردن قرآن..."
+ keeps "تشبیه کردن قرآن...") - returns "" when there is nothing worth indexing
+
+
+
+
+
make plain text
+ poem/section title - its searchable part (if any) is included so
+ titles like "بخش ۴۷ - تشبیه کردن ..." are findable through search, while pure
+ boilerplate like "غزل شمارهٔ ۱" is silently skipped