Skip to content
This repository has been archived by the owner on Jan 21, 2025. It is now read-only.

[Multipart] add test case with HttpPart #613

Merged
merged 22 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/lemon-fireants-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@azure-tools/cadl-ranch-specs": patch
---

Add test case with `HttpPart` for multipart
96 changes: 85 additions & 11 deletions packages/cadl-ranch-specs/cadl-ranch-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -2567,29 +2567,36 @@ Content-Type: application/octet-stream
--abcde12345--
```

### Payload_MultiPart_FormData_jsonArrayParts
### Payload_MultiPart_FormData_complexWithHttpPart
msyyc marked this conversation as resolved.
Show resolved Hide resolved

- Endpoint: `post /multipart/form-data/json-array-parts`
- Endpoint: `post /multipart/form-data/complex-parts-with-httppart`

Expect request (

- according to https://datatracker.ietf.org/doc/html/rfc7578#section-4.4, content-type of file part shall be labeled with
appropriate media type, cadl-ranch will check it; content-type of other parts is optional, cadl-ranch will ignore it.
- according to https://datatracker.ietf.org/doc/html/rfc7578#section-4.2, filename of file part SHOULD be supplied.
If there are duplicated filename in same fieldName, cadl-ranch can't parse them all.
):
For File part, filename will not be checked but it is necessary otherwise cadl-ranch can't parse it;
content-type will be checked with value "application/octet-stream". Expect request:

```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-or-no-name-is-ok>"
Content-Disposition: form-data; name="id"
Content-Type: text/plain

123
--abcde12345
Content-Disposition: form-data; name="address"
Content-Type: application/json

{
"city": "X"
}
--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345
--abcde12345--
Content-Disposition: form-data; name="previousAddresses"
Content-Type: application/json

Expand All @@ -2598,6 +2605,73 @@ Content-Type: application/json
},{
"city": "Z"
}]
--abcde12345
Content-Disposition: form-data; name="pictures"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345
Content-Disposition: form-data; name="pictures"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345--
```

### Payload_MultiPart_FormData_fileWithHttpPartOptionalContentType

- Endpoint: `post /multipart/form-data/file-with-http-part-optional-content-type`

Please send request twice, first time with no content-type and second time with content-type "application/octet-stream". Expect request:

```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345
```

### Payload_MultiPart_FormData_fileWithHttpPartRequiredContentType

- Endpoint: `post /multipart/form-data/check-filename-and-required-content-type-with-httppart`

This case will check required content-type of file part, so expect request:

```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345--
```

### Payload_MultiPart_FormData_fileWithHttpPartSpecificContentType

- Endpoint: `post /multipart/form-data/check-filename-and-specific-content-type-with-httppart`

This case will check filename and specific content-type of file part, so expect request:

```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="hello.jpg"
Content-Type: image/jpg

{…file content…}
--abcde12345--
```

Expand Down
199 changes: 162 additions & 37 deletions packages/cadl-ranch-specs/http/payload/multipart/main.tsp
msyyc marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,44 @@ model Address {
city: string;
}

model FileSpecificContentType extends File {
filename: string;
contentType: "image/jpg";
}

model FileWithHttpPartSpecificContentTypeRequest {
profileImage: HttpPart<FileSpecificContentType>;
}

model FileRequiredMetaData extends File {
filename: string;
contentType: string;
}

model FileWithHttpPartRequiredContentTypeRequest {
profileImage: HttpPart<FileRequiredMetaData>;
}

model FileOptionalContentType extends File {
filename: string;
}

model FileWithHttpPartOptionalContentTypeRequest {
profileImage: HttpPart<FileOptionalContentType>;
}

model ComplexHttpPartsModelRequest {
id: HttpPart<string>;
address: HttpPart<Address>;
profileImage: HttpPart<FileRequiredMetaData>;
previousAddresses: HttpPart<Address[]>;
pictures: HttpPart<FileRequiredMetaData>[];
msyyc marked this conversation as resolved.
Show resolved Hide resolved
}

model ComplexPartsRequest {
id: string;
address: Address;
profileImage: bytes;
previousAddresses: Address[];
pictures: bytes[];
}

Expand All @@ -36,7 +69,6 @@ model BinaryArrayPartsRequest {

model JsonArrayPartsRequest {
profileImage: bytes;
previousAddresses: Address[];
}

model MultiBinaryPartsRequest {
Expand Down Expand Up @@ -206,41 +238,6 @@ Content-Type: application/octet-stream
@body body: BinaryArrayPartsRequest,
): NoContentResponse;

@scenario
@scenarioDoc("""
Expect request (
- according to https://datatracker.ietf.org/doc/html/rfc7578#section-4.4, content-type of file part shall be labeled with
appropriate media type, cadl-ranch will check it; content-type of other parts is optional, cadl-ranch will ignore it.
- according to https://datatracker.ietf.org/doc/html/rfc7578#section-4.2, filename of file part SHOULD be supplied.
If there are duplicated filename in same fieldName, cadl-ranch can't parse them all.
):
```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-or-no-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345
Content-Disposition: form-data; name="previousAddresses"
Content-Type: application/json

[{
"city": "Y"
},{
"city": "Z"
}]
--abcde12345--
```
""")
@doc("Test content-type: multipart/form-data for scenario contains multi json parts")
@post
@route("/json-array-parts")
op jsonArrayParts(@header contentType: "multipart/form-data", @body body: JsonArrayPartsRequest): NoContentResponse;

@scenario
@scenarioDoc("""
Please send request twice, first time with only profileImage, second time with both profileImage and picture(
Expand Down Expand Up @@ -332,4 +329,132 @@ Content-Type: application/octet-stream;
@header contentType: "multipart/form-data",
profileImage: MultiPartRequest.profileImage,
): NoContentResponse;

@scenario
@scenarioDoc("""
This case will check filename and specific content-type of file part, so expect request:
```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="hello.jpg"
Content-Type: image/jpg

{…file content…}
--abcde12345--
```
""")
@doc("Test content-type: multipart/form-data")
@post
@route("/check-filename-and-specific-content-type-with-httppart")
op fileWithHttpPartSpecificContentType(
@header contentType: "multipart/form-data",
@body body: FileWithHttpPartSpecificContentTypeRequest,
): NoContentResponse;

@scenario
@scenarioDoc("""
This case will check required content-type of file part, so expect request:
```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345--
```
""")
@doc("Test content-type: multipart/form-data")
@post
@route("/check-filename-and-required-content-type-with-httppart")
op fileWithHttpPartRequiredContentType(
@header contentType: "multipart/form-data",
@body body: FileWithHttpPartRequiredContentTypeRequest,
): NoContentResponse;

@scenario
@scenarioDoc("""
Please send request twice, first time with no content-type and second time with content-type "application/octet-stream". Expect request:
```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345
```
""")
@doc("Test content-type: multipart/form-data for optional content type")
@post
@route("/file-with-http-part-optional-content-type")
op fileWithHttpPartOptionalContentType(
@header contentType: "multipart/form-data",
@multipartBody body: FileWithHttpPartOptionalContentTypeRequest,
): NoContentResponse;

@scenario
@scenarioDoc("""
For File part, filename will not be checked but it is necessary otherwise cadl-ranch can't parse it;
content-type will be checked with value "application/octet-stream". Expect request:
```
POST /upload HTTP/1.1
Content-Length: 428
Content-Type: multipart/form-data; boundary=abcde12345

--abcde12345
Content-Disposition: form-data; name="id"
Content-Type: text/plain

123
--abcde12345
Content-Disposition: form-data; name="address"
Content-Type: application/json

{
"city": "X"
}
--abcde12345
Content-Disposition: form-data; name="profileImage"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
--abcde12345--
Content-Disposition: form-data; name="previousAddresses"
Content-Type: application/json

[{
"city": "Y"
},{
"city": "Z"
}]
--abcde12345
Content-Disposition: form-data; name="pictures"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
msyyc marked this conversation as resolved.
Show resolved Hide resolved
--abcde12345
Content-Disposition: form-data; name="pictures"; filename="<any-name-is-ok>"
Content-Type: application/octet-stream

{…file content…}
msyyc marked this conversation as resolved.
Show resolved Hide resolved
--abcde12345--
```
""")
@doc("Test content-type: multipart/form-data for mixed scenarios")
@post
@route("/complex-parts-with-httppart")
op complexWithHttpPart(
@header contentType: "multipart/form-data",
@body body: ComplexHttpPartsModelRequest,
): NoContentResponse;
}
Loading
Loading