From dd3f9131a3f2c5ae5345e5765b9b08c92f973469 Mon Sep 17 00:00:00 2001 From: Andrii Kurdiumov Date: Sat, 15 Jul 2023 23:21:32 +0600 Subject: [PATCH] Add support for plain control types Closes: #1193 --- src/FSharp.Data.Http/Http.fs | 41 +++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/FSharp.Data.Http/Http.fs b/src/FSharp.Data.Http/Http.fs index 95411fef6..78b1a6dfc 100644 --- a/src/FSharp.Data.Http/Http.fs +++ b/src/FSharp.Data.Http/Http.fs @@ -636,6 +636,11 @@ module HttpStatusCodes = type MultipartItem = MultipartItem of formField: string * filename: string * content: Stream +type MultipartFileItem = MultipartFileItem of formField: string * filename: string option * contentType: string option * content: Stream + +type MultipartFormDataItem = + | FileValue of MultipartFileItem + | FormValue of string * string /// The body to send in an HTTP request type HttpRequestBody = @@ -649,6 +654,9 @@ type HttpRequestBody = /// A sequence of formParamName * fileName * fileContent groups | Multipart of boundary: string * parts: seq + /// A sequence of formParamName * fileName * fileContent groups + | MultipartFormData of boundary: string * parts: seq + /// The response body returned by an HTTP request type HttpResponseBody = | Text of string @@ -1521,7 +1529,7 @@ module internal HttpHelpers = /// c) write newline /// d) write section data /// 3) write trailing boundary - let writeMultipart (boundary: string) (parts: seq) (e: Encoding) = + let writeMultipart (boundary: string) (parts: seq) (e: Encoding) = let newlineStream () = new MemoryStream(e.GetBytes "\r\n") :> Stream @@ -1545,17 +1553,20 @@ module internal HttpHelpers = let segments = parts - |> Seq.map (fun (MultipartItem (formField, fileName, contentStream)) -> - let fileExt = Path.GetExtension fileName - let contentType = defaultArg (MimeTypes.tryFind fileExt) "application/octet-stream" + |> Seq.map (fun (MultipartFileItem(formField, fileName, contentType, contentStream)) -> let printHeader (header, value) = sprintf "%s: %s" header value + let sharedHeaders = [ + prefixedBoundary + HttpRequestHeaders.ContentDisposition("form-data", Some formField, fileName) + |> printHeader ] + let headers = match contentType with + | Some(contentType) -> + sharedHeaders + |> Seq.append [ HttpRequestHeaders.ContentType contentType |> printHeader ] + | None -> sharedHeaders let headerpart = - [ prefixedBoundary - HttpRequestHeaders.ContentDisposition("form-data", Some formField, Some fileName) - |> printHeader - HttpRequestHeaders.ContentType contentType - |> printHeader ] + headers |> String.concat "\r\n" let headerStream = @@ -2079,7 +2090,17 @@ type Http private () = |> e.GetBytes HttpContentTypes.FormValues, (fun e -> new MemoryStream(bytes e) :> _) - | Multipart (boundary, parts) -> HttpContentTypes.Multipart(boundary), writeMultipart boundary parts + | Multipart (boundary, parts) -> + let fileParts = parts |> Seq.map (fun (MultipartItem(formField, fileName, stream)) -> + let fileExt = Path.GetExtension fileName + let contentType = defaultArg (MimeTypes.tryFind fileExt) "application/octet-stream" + MultipartFileItem(formField, Some fileName, Some contentType, stream)) + HttpContentTypes.Multipart(boundary), writeMultipart boundary fileParts + | MultipartFormData (boundary, parts) -> + let fileParts = parts |> Seq.map (fun p -> match p with + | FormValue(formField, value) -> MultipartFileItem(formField, None, None, new MemoryStream(Encoding.UTF8.GetBytes(value))) + | FileValue(item) -> item) + HttpContentTypes.Multipart(boundary), writeMultipart boundary fileParts // Set default content type if it is not specified by the user let encoding =