Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multipart form-data #4613

Merged
merged 58 commits into from Apr 26, 2024
Merged

Multipart form-data #4613

merged 58 commits into from Apr 26, 2024

Conversation

chunyu3
Copy link
Member

@chunyu3 chunyu3 commented Apr 22, 2024

Description

Fix #4339
Fix #4340
Fix #4338

  • implement multipart/form-data
  • Codegen will generate core library MultipartFormDataRequestConent for azure, and MultipartFormDataBinaryContent for non-azure
  • each model will generate ToMultipartRequestContent to serialize model to multipart/form-data format
  • Add contentType parameter in protocol method
  • Convenience method will generate MultipartFormDataRequestContent/MultipartFormDataBinaryContent from model and call protocol method.

Checklist

To ensure a quick review and merge, please ensure:

  • The PR has a understandable title and description explaining the why and what.
  • The PR is opened in draft if not ready for review yet.
    • If opened in draft, please allocate sufficient time (24 hours) after moving out of draft for review
  • The branch is recent enough to not have merge conflicts upon creation.

Ready to Land?

  • Build is completely green
    • Submissions with test failures require tracking issue and approval of a CODEOWNER
  • At least one +1 review by a CODEOWNER
  • All -1 reviews are confirmed resolved by the reviewer
    • Override/Marking reviews stale must be discussed with CODEOWNERS first

…ionMethodsBuilder.cs

Co-authored-by: Dapeng Zhang <ufo54153@gmail.com>
@chunyu3 chunyu3 merged commit dac2fba into Azure:feature/v3 Apr 26, 2024
8 checks passed
internal virtual MultipartFormDataBinaryContent ToMultipartBinaryBody()
{
MultipartFormDataBinaryContent content = new MultipartFormDataBinaryContent();
content.Add(File, "file", "file", "application/octet-stream");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not pass a value for filename here if there is no file name.

content.Add(Image, "image", "image", "application/octet-stream");
if (Optional.IsDefined(Mask))
{
content.Add(Mask, "mask", "mask", "application/octet-stream");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not work -- OpenAI needs to be able to pass the file name to this method to correctly format the header for the Mask property in the multipart/form-data content payload.

/// <param name="options"> The request options, which can override default behaviors of the client pipeline on a per-call basis. </param>
/// <exception cref="ArgumentNullException"> <paramref name="content"/> is null. </exception>
/// <exception cref="ClientResultException"> Service returned a non-success status code. </exception>
/// <returns> The response returned from the service. </returns>
public virtual async Task<ClientResult> CreateAsync(BinaryContent content, RequestOptions options = null)
public virtual async Task<ClientResult> CreateAsync(BinaryContent content, string contentType, RequestOptions options = null)
{
Argument.AssertNotNull(content, nameof(content));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add Assert.NotNullOrEmpty(contentType, nameof(contentType)); here -- I think I had left this out of the original design. Thanks to @joseharriaga for catching this!

internal virtual MultipartFormDataBinaryContent ToMultipartBinaryBody()
{
MultipartFormDataBinaryContent content = new MultipartFormDataBinaryContent();
content.Add(File, "file", "file", "application/octet-stream");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also not be hard-coding the content-type here.

{
get
{
return _multipartContent.Headers.ContentType.ToString();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the Debug.Assert(_multipartContent.Headers.ContentType is not null); was missed here from the design spec

Span<char> chars = new char[70];
byte[] random = new byte[70];
_random.NextBytes(random);
int mask = 255 >> 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the comment explaining this is missing.

byte[] random = new byte[70];
_random.NextBytes(random);
int mask = 255 >> 2;
for (int i = 0; i < 70; i++)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a Debug.Assert(_boundaryValues.Length - 1 == mask); preceding this line.

Argument.AssertNotNull(content, nameof(content));
Argument.AssertNotNullOrEmpty(name, nameof(name));

string value = content.ToString("G", CultureInfo.InvariantCulture);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is missing from this line.


public static void AddFilenameHeader(HttpContent content, string name, string filename)
{
ContentDispositionHeaderValue header = new ContentDispositionHeaderValue("form-data") { Name = name, FileName = filename };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is missing from this method.


public static void AddContentTypeHeader(HttpContent content, string contentType)
{
MediaTypeHeaderValue header = new MediaTypeHeaderValue(contentType);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we adding this in a separate method? I don't believe this is needed and should be removed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each part(not just file) of the multipart/form-data payload may set the content-type to indicate its content type(see following example). We need provide a way to set content-type of a part.
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BCL type will do this automatically for you.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BCL type will give default one. The request is customer can specify the content-type to each part.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants