diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index bb03368b4..3c7b3733e 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,10 @@ # Release Notes +## 8.1.1 - Mar 14 2026 + +- Fix `CombinedStream` to throw `NotSupportedException` (instead of `Exception`) for unsupported operations (write, seek, set length); fixes a typo in the length error message +- Rename shadowed inner `isText` helper to `isMimeTypeText` for code clarity; add explanatory comment + ## 8.1.0 - Mar 08 2026 - Add schema.org microdata support to `HtmlProvider`: when an HTML document contains elements with `itemscope`/`itemtype`/`itemprop` attributes, the provider now generates a typed `Schemas` container (e.g. `doc.Schemas.Person`) with one strongly-typed property per `itemprop` name discovered in the sample (closes #611) diff --git a/src/FSharp.Data.Http/Http.fs b/src/FSharp.Data.Http/Http.fs index 8cc2f09c0..52c67d53c 100644 --- a/src/FSharp.Data.Http/Http.fs +++ b/src/FSharp.Data.Http/Http.fs @@ -1499,18 +1499,31 @@ module internal HttpHelpers = override x.Length = length |> Option.defaultWith (fun () -> - failwith "One or more of the encompassed streams are not seekable and the length cannot be determine") + raise ( + NotSupportedException( + "One or more of the encompassed streams are not seekable and the length cannot be determined" + ) + )) override x.Position with get () = v - and set (_) = failwith "no position setting" + and set (_) = raise (NotSupportedException("CombinedStream does not support seeking")) override x.Flush() = () override x.CanTimeout = false - override x.Seek(_, _) = failwith "no seeking" - override x.SetLength(_) = failwith "no setting length" - override x.Write(_, _, _) = failwith "no writing" - override x.WriteByte(_) = failwith "seriously, no writing" + + override x.Seek(_, _) = + raise (NotSupportedException("CombinedStream does not support seeking")) + + override x.SetLength(_) = + raise (NotSupportedException("CombinedStream does not support setting length")) + + override x.Write(_, _, _) = + raise (NotSupportedException("CombinedStream is read-only")) + + override x.WriteByte(_) = + raise (NotSupportedException("CombinedStream is read-only")) + override x.Read(buffer, offset, count) = readFromStream buffer offset count interface IDisposable with @@ -1804,7 +1817,7 @@ module internal HttpHelpers = async { let isText (mimeType: string) = - let isText (mimeType: string) = + let isMimeTypeText (mimeType: string) = let mimeType = mimeType.Trim() mimeType.StartsWith("text/", StringComparison.Ordinal) @@ -1819,8 +1832,9 @@ module internal HttpHelpers = || mimeType.StartsWith("application/", StringComparison.Ordinal) && mimeType.EndsWith("+json", StringComparison.Ordinal) + // Split on ';' to ignore MIME type parameters (e.g. "text/html; charset=utf-8") mimeType.Split([| ';' |], StringSplitOptions.RemoveEmptyEntries) - |> Array.exists isText + |> Array.exists isMimeTypeText let! memoryStream = asyncRead stream diff --git a/tests/FSharp.Data.Core.Tests/Http.fs b/tests/FSharp.Data.Core.Tests/Http.fs index 61cb29b41..a8524f121 100644 --- a/tests/FSharp.Data.Core.Tests/Http.fs +++ b/tests/FSharp.Data.Core.Tests/Http.fs @@ -366,7 +366,7 @@ let ``CombinedStream can seek with Some length`` () = [] let ``CombinedStream length throws with None length`` () = use combinedStream = new HttpHelpers.CombinedStream(None, []) - (fun () -> combinedStream.Length |> ignore) |> should throw typeof + (fun () -> combinedStream.Length |> ignore) |> should throw typeof [] let ``CombinedStream cannot seek with None length`` () = @@ -383,7 +383,7 @@ let ``Non-seekable streams create non-seekable CombinedStream`` () = use nonSeekms = new nonSeekableStream(Array.zeroCreate 10) let multiparts = [MultipartItem("","", nonSeekms)] let combinedStream = HttpHelpers.writeMultipart "-" multiparts Encoding.UTF8 - (fun () -> combinedStream.Length |> ignore) |> should throw typeof + (fun () -> combinedStream.Length |> ignore) |> should throw typeof combinedStream.CanSeek |> should equal false []