jetty-reactive-httpclient icon indicating copy to clipboard operation
jetty-reactive-httpclient copied to clipboard

Add support of multipart form data

Open kptfh opened this issue 2 years ago • 9 comments

Provide utility method Request.Content.fromParts(Publisher<Part>)

where Part

public interface Part {

	/**
	 * Return the name of the part in the multipart form.
	 * @return the name of the part, never {@code null} or empty
	 */
	String name();

	/**
	 * Return the headers associated with the part.
	 */
	HttpHeaders headers();

	/**
	 * Return the content for this part.
	 * <p>Note that for a {@link FormFieldPart} the content may be accessed
	 * more easily via {@link FormFieldPart#value()}.
	 */
	Flux<DataBuffer> content();

	/**
	 * Return a mono that, when subscribed to, deletes the underlying storage
	 * for this part.
	 * @since 5.3.13
	 */
	default Mono<Void> delete() {
		return Mono.empty();
	}

}

kptfh avatar Mar 29 '22 08:03 kptfh

Can you clarify whether Part is a class from some other library, or I should provide one in this project?

I would also need a use case.

Is this similar to HttpClient's MultiPartRequestContent, but reactive?

sbordet avatar Mar 29 '22 16:03 sbordet

Took this Part interface from Spring. Don't know if there is analogue interface in Jetty. I'd like to add this functionality to jetty based reactive feign module

kptfh avatar Mar 29 '22 21:03 kptfh

Is this similar to HttpClient's MultiPartRequestContent, but reactive?

Exactly

kptfh avatar Mar 29 '22 21:03 kptfh

Upvoting this

patpatpat123 avatar May 12 '23 06:05 patpatpat123

We have https://github.com/eclipse/jetty.project/blob/f98b345a28fcefbf1fa8e16dc4b44605b68f2c62/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java#L122 which is vaguely similar.

However, I do not think we make available a stream of those parts, only the collection of all Parts once read. It should be possible to stream the parts, but the tricky issue will be that we would need to deliver the part before it's content was complete, and then allow the recipient to stream the content.

If we do this, it would likely be in the form of a jetty-12 style demand interface, but that is trivially convertible to a Publisher.

@lachlan-roberts thoughts?

gregw avatar May 12 '23 14:05 gregw

@gregw I don't think this issue is asking to be able to stream the parts which have been received, but to publish parts to be sent into a Request.Content.

But I think this is easily done. I think this should work?

static Content fromParts(Flow.Publisher<MultiPart.Part> publisher)
{
    MultiPartRequestContent content = new MultiPartRequestContent();
    publisher.subscribe(new Flow.Subscriber<>()
    {
        private Flow.Subscription _subscription;

        @Override
        public void onSubscribe(Flow.Subscription subscription)
        {
            _subscription = subscription;
            _subscription.request(1);
        }

        @Override
        public void onNext(MultiPart.Part item)
        {
            content.addPart(item);
            _subscription.request(1);
        }

        @Override
        public void onError(Throwable throwable)
        {
            content.fail(throwable);
        }

        @Override
        public void onComplete()
        {
            content.close();
        }
    });

    return content;
}

lachlan-roberts avatar May 15 '23 05:05 lachlan-roberts

@lachlan-roberts yes the idea is correct, but we don't have MultiPart.Part in Jetty 10/11, only in 12. So perhaps we add this in the 4.x series of this project, based on Jetty 12.

sbordet avatar May 15 '23 08:05 sbordet

@gregw I don't think this issue is asking to be able to stream the parts which have been received, but to publish parts to be sent into a Request.Content.

By "stream the parts" I mean publish them through a Flow.

Are you sure this is a publish parts sent, rather than to be subscribed to parts received? Actually surely we need both?

gregw avatar May 15 '23 14:05 gregw

@gregw this is the reactive client, so we need the "reactive" to both send and receive, although the receive part must be done by the application, so we can only provide utilities to take a reactive response body and turn it into reactive parts.

sbordet avatar May 15 '23 14:05 sbordet