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

Bug with multipart boundary field value when re-using the FlurlRequest object #807

Open
lmb-djaquier opened this issue Jan 29, 2024 · 2 comments
Labels

Comments

@lmb-djaquier
Copy link

lmb-djaquier commented Jan 29, 2024

Hello,

I found incorrect Flurl behavior when re-using a Flurlrequest object with multiple PostMultipartAsyncs.

For example, with this kind of snippet, to fetch some attachments from a famous support case manager (service now) to sync with a famous other ticketing system (jira):

var jiraAddAttachmentUrl = jiraCreateIssueResponse.Self
.AppendPathSegment("attachments")
.WithSomeNiceStuff(...)
;

foreach (var currentAttachmentToAdd in snowParentAttachmentResult.Result)
{
    using (var processSingleAttachment = myActivitySource.StartActivity("Get single attachment"))
    {

        var currentAttachmentSnowUrl = SnowRootUrl
            .AppendPathSegment("api/now/attachment")
            .WithSomeNiceStuff(...)

        Stream currentAttachmentStream;

        using (var getAttachmentFromSnow = myActivitySource.StartActivity("Get File from Service Now"))
        {
            currentAttachmentStream = await currentAttachmentSnowUrl.GetStreamAsync();
        }
        using (var addFileInJira = myActivitySource.StartActivity("Post file to jira"))
        {
            var jiraAddAttachmentResponse = await jiraAddAttachmentUrl.PostMultipartAsync(mp => mp
            .AddFile("file", currentAttachmentStream, currentAttachmentToAdd.FileName)
            );
        }
    }
}

For the first iteration in fiddler/wireshark, everything seems fine

POST <jira url>/rest/api/2/issue/1324008/attachments HTTP/1.1
Host: XXXXXXXXXX
Authorization: Basic XXXXXXXXX
X-Atlassian-Token: nocheck
Transfer-Encoding: chunked
Accept-Encoding: gzip, deflate
traceparent: 00-85995a13445359dc837ac6793c3f94d6-1939b112bcbdbeed-01
Content-Type: multipart/form-data; boundary="6553d643-ca40-434f-a980-7253ee239492"

28
--6553d643-ca40-434f-a980-7253ee239492

4D
Content-Disposition: form-data; name="file"; filename="XXXXX.xlsx"

But, when the stream is updated and we try to recycle the FlurlRequest object, boundary is not changed (still 6553d643-ca40-434f-a980-7253ee239492 ). That means the pointer is wrong and the server has no content to handle. In that case, no attachement in the ticketing system.

POST <jira url>/rest/api/2/issue/1324008/attachments HTTP/1.1
Host: XXXXXXXXXX
Authorization: Basic XXXXXXXXX
X-Atlassian-Token: nocheck
Transfer-Encoding: chunked
Accept-Encoding: gzip, deflate
traceparent: 00-85995a13445359dc837ac6793c3f94d6-2bc66332b9f05488-01
Content-Type: multipart/form-data; boundary="6553d643-ca40-434f-a980-7253ee239492"

28
--a8ffd831-4f29-4763-b834-9e76b03ce26d

59
Content-Disposition: form-data; name="file"; filename="XXXXXXXX.log"

Is that a bug or something missed on our side?

I fixed it currently with a re-instanciation of the object inside the loop.

@lmb-djaquier lmb-djaquier changed the title Bug with multipart boundary field value when the same Bug with multipart boundary field value when re-using the FlurlRequest object Jan 29, 2024
@tmenier
Copy link
Owner

tmenier commented Jan 29, 2024

A FlurlRequest should never be reused. Much like the HttpRequestMessage that it effectively wraps, it's underpinned by a forward-only stream. The rules mirror those of the HttpClient stack: reuse clients heavily; never reuse requests. Your fix of creating a new one is correct.

@romerod
Copy link

romerod commented Feb 5, 2024

Ah ok, explained like that it makes sense.

With the fluent interface it's actually not that visible that a request is created:

var jiraAddAttachmentUrl = jiraCreateIssueResponse.Self
.AppendPathSegment("attachments");
or
url.WithHeader("Accept", "text/plain")

One might be tempted to reuse a request.

Might be helpful to add this information to the documentation or maybe even throw an Exception in case of PostMultipartAsync as the sent request is not usable.

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

No branches or pull requests

3 participants