Skip to content

Commit 066a7f3

Browse files
authored
Merge pull request #1487 from kant2002/kant/multipart
2 parents 5088a47 + 649b0e0 commit 066a7f3

3 files changed

Lines changed: 56 additions & 11 deletions

File tree

.github/workflows/pull-requests.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
branches:
66
- main
77

8+
89
jobs:
910
build-windows:
1011

@@ -20,6 +21,8 @@ jobs:
2021
- name: Restore packages
2122
run: dotnet paket restore
2223
- name: Build and test (Release)
24+
env:
25+
FAKE_DETAILED_ERRORS: true
2326
run: dotnet fake build -t All
2427
- name: Build (Debug)
2528
run: dotnet build -c Debug -v n

build.fsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ Target.create "Help" (fun _ ->
184184
printfn ""
185185
printfn " Other targets:"
186186
printfn " * CleanInternetCaches"
187+
printfn " * Format"
188+
printfn " * CheckFormat"
187189
printfn "")
188190

189191
let sourceFiles =

src/FSharp.Data.Http/Http.fs

Lines changed: 51 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,13 @@ module HttpStatusCodes =
637637

638638
type MultipartItem = MultipartItem of formField: string * filename: string * content: Stream
639639

640+
type MultipartFileItem =
641+
| MultipartFileItem of formField: string * filename: string option * contentType: string option * content: Stream
642+
643+
type MultipartFormDataItem =
644+
| FileValue of MultipartFileItem
645+
| FormValue of string * string
646+
640647
/// The body to send in an HTTP request
641648
type HttpRequestBody =
642649

@@ -649,6 +656,9 @@ type HttpRequestBody =
649656
/// A sequence of formParamName * fileName * fileContent groups
650657
| Multipart of boundary: string * parts: seq<MultipartItem>
651658

659+
/// A sequence of formParamName * fileName * fileContent groups
660+
| MultipartFormData of boundary: string * parts: seq<MultipartFormDataItem>
661+
652662
/// The response body returned by an HTTP request
653663
type HttpResponseBody =
654664
| Text of string
@@ -1521,7 +1531,7 @@ module internal HttpHelpers =
15211531
/// c) write newline
15221532
/// d) write section data
15231533
/// 3) write trailing boundary
1524-
let writeMultipart (boundary: string) (parts: seq<MultipartItem>) (e: Encoding) =
1534+
let writeMultipartFileItem (boundary: string) (parts: seq<MultipartFileItem>) (e: Encoding) =
15251535
let newlineStream () =
15261536
new MemoryStream(e.GetBytes "\r\n") :> Stream
15271537

@@ -1545,18 +1555,23 @@ module internal HttpHelpers =
15451555

15461556
let segments =
15471557
parts
1548-
|> Seq.map (fun (MultipartItem (formField, fileName, contentStream)) ->
1549-
let fileExt = Path.GetExtension fileName
1550-
let contentType = defaultArg (MimeTypes.tryFind fileExt) "application/octet-stream"
1558+
|> Seq.map (fun (MultipartFileItem (formField, fileName, contentType, contentStream)) ->
15511559
let printHeader (header, value) = sprintf "%s: %s" header value
15521560

1553-
let headerpart =
1554-
[ prefixedBoundary
1555-
HttpRequestHeaders.ContentDisposition("form-data", Some formField, Some fileName)
1556-
|> printHeader
1557-
HttpRequestHeaders.ContentType contentType
1558-
|> printHeader ]
1559-
|> String.concat "\r\n"
1561+
let headers =
1562+
match contentType with
1563+
| Some (contentType) ->
1564+
[ prefixedBoundary
1565+
HttpRequestHeaders.ContentDisposition("form-data", Some formField, fileName)
1566+
|> printHeader
1567+
HttpRequestHeaders.ContentType contentType
1568+
|> printHeader ]
1569+
| None ->
1570+
[ prefixedBoundary
1571+
HttpRequestHeaders.ContentDisposition("form-data", Some formField, fileName)
1572+
|> printHeader ]
1573+
1574+
let headerpart = headers |> String.concat "\r\n"
15601575

15611576
let headerStream =
15621577
let bytes = e.GetBytes headerpart
@@ -1583,6 +1598,16 @@ module internal HttpHelpers =
15831598
let wholePayloadLength = wholePayload |> trySumLength
15841599
new CombinedStream(wholePayloadLength, wholePayload) :> Stream
15851600

1601+
let writeMultipart (boundary: string) (parts: seq<MultipartItem>) (e: Encoding) =
1602+
let fileParts =
1603+
parts
1604+
|> Seq.map (fun (MultipartItem (formField, fileName, stream)) ->
1605+
let fileExt = Path.GetExtension fileName
1606+
let contentType = defaultArg (MimeTypes.tryFind fileExt) "application/octet-stream"
1607+
MultipartFileItem(formField, Some fileName, Some contentType, stream))
1608+
1609+
writeMultipartFileItem boundary fileParts e
1610+
15861611
let asyncCopy (source: Stream) (dest: Stream) =
15871612
async {
15881613
do!
@@ -2080,6 +2105,21 @@ type Http private () =
20802105

20812106
HttpContentTypes.FormValues, (fun e -> new MemoryStream(bytes e) :> _)
20822107
| Multipart (boundary, parts) -> HttpContentTypes.Multipart(boundary), writeMultipart boundary parts
2108+
| MultipartFormData (boundary, parts) ->
2109+
let fileParts =
2110+
parts
2111+
|> Seq.map (fun p ->
2112+
match p with
2113+
| FormValue (formField, value) ->
2114+
MultipartFileItem(
2115+
formField,
2116+
None,
2117+
None,
2118+
new MemoryStream(Encoding.UTF8.GetBytes(value))
2119+
)
2120+
| FileValue (item) -> item)
2121+
2122+
HttpContentTypes.Multipart(boundary), writeMultipartFileItem boundary fileParts
20832123

20842124
// Set default content type if it is not specified by the user
20852125
let encoding =

0 commit comments

Comments
 (0)