All Downloads are FREE. Search and download functionalities are using the official Maven repository.

reactor.netty.http.client.HttpClientFormEncoder Maven / Gradle / Ivy

There is a newer version: 1.2.1
Show newest version
/*
 * Copyright (c) 2011-2023 VMware, Inc. or its affiliates, All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package reactor.netty.http.client;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;

import io.netty.buffer.ByteBufAllocator;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.multipart.DiskAttribute;
import io.netty.handler.codec.http.multipart.DiskFileUpload;
import io.netty.handler.codec.http.multipart.FileUpload;
import io.netty.handler.codec.http.multipart.HttpDataFactory;
import io.netty.handler.codec.http.multipart.HttpPostRequestEncoder;
import io.netty.handler.stream.ChunkedInput;
import reactor.core.Exceptions;
import reactor.core.publisher.Sinks;
import reactor.util.annotation.Nullable;

/**
 * Modified {@link io.netty.handler.codec.http.multipart.HttpPostRequestEncoder} for
 * optional filename and builder support
 * 

* This encoder will help to encode Request for a FORM as POST. */ final class HttpClientFormEncoder extends HttpPostRequestEncoder implements ChunkedInput, Runnable, HttpClientForm { final Sinks.Many progressSink; final HttpRequest request; boolean needNewEncoder; HttpDataFactory newFactory; boolean cleanOnTerminate; Charset newCharset; boolean newMultipart; EncoderMode newMode; /** * Constructs a new {@link HttpClientFormEncoder}. * * @param factory the factory used to create InterfaceHttpData * @param request the request to encode * @param multipart True if the FORM is a ENCTYPE="multipart/form-data" * @param charset the charset to use as default * @param encoderMode the mode for the encoder to use. See {@link EncoderMode} for the * details. * * @throws NullPointerException for request or charset or factory * @throws ErrorDataEncoderException if the request is not a POST */ HttpClientFormEncoder(HttpDataFactory factory, HttpRequest request, boolean multipart, Charset charset, EncoderMode encoderMode) throws ErrorDataEncoderException { super(factory, request, multipart, charset, encoderMode); this.newCharset = charset; this.request = request; this.cleanOnTerminate = true; this.progressSink = Sinks.many().unicast().onBackpressureError(); this.newMode = encoderMode; this.newFactory = factory; this.newMultipart = multipart; } @Override public HttpContent readChunk(ByteBufAllocator allocator) throws Exception { HttpContent c = super.readChunk(allocator); if (c == null) { progressSink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST); } else { progressSink.emitNext(progress(), Sinks.EmitFailureHandler.FAIL_FAST); if (isEndOfInput()) { progressSink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST); } } return c; } @Override public HttpClientForm attr(String name, String value) { try { addBodyAttribute(name, value); } catch (ErrorDataEncoderException e) { throw Exceptions.propagate(e); } return this; } @Override public HttpClientForm charset(Charset charset) { this.newCharset = Objects.requireNonNull(charset, "charset"); this.needNewEncoder = true; return this; } @Override public HttpClientForm cleanOnTerminate(boolean clean) { this.cleanOnTerminate = clean; return this; } @Override public HttpClientForm factory(HttpDataFactory factory) { if (!getBodyListAttributes().isEmpty()) { throw new IllegalStateException("Cannot set a new HttpDataFactory after " + "starting appending Parts, call factory(f) at the earliest occasion" + " offered"); } this.newFactory = Objects.requireNonNull(factory, "factory"); this.needNewEncoder = true; return this; } @Override public HttpClientForm file(String name, File file) { file(name, file, null); return this; } @Override public HttpClientForm file(String name, InputStream inputStream) { file(name, inputStream, null); return this; } @Override public HttpClientForm file(String name, String filename, File file, @Nullable String contentType) { Objects.requireNonNull(name, "name"); Objects.requireNonNull(file, "file"); Objects.requireNonNull(filename, "filename"); String scontentType = contentType; if (contentType == null) { scontentType = DEFAULT_BINARY_CONTENT_TYPE; } FileUpload fileUpload = newFactory.createFileUpload(request, name, filename, scontentType, DEFAULT_TRANSFER_ENCODING, null, file.length()); try { fileUpload.setContent(file); addBodyHttpData(fileUpload); } catch (ErrorDataEncoderException e) { throw Exceptions.propagate(e); } catch (IOException e) { throw Exceptions.propagate(new ErrorDataEncoderException(e)); } return this; } @Override public HttpClientForm file(String name, String filename, InputStream stream, @Nullable String contentType) { Objects.requireNonNull(name, "name"); Objects.requireNonNull(stream, "stream"); try { String scontentType = contentType; if (contentType == null) { scontentType = DEFAULT_BINARY_CONTENT_TYPE; } FileUpload fileUpload = newFactory.createFileUpload(request, name, filename, scontentType, DEFAULT_TRANSFER_ENCODING, newCharset, -1); fileUpload.setMaxSize(-1); fileUpload.setContent(stream); addBodyHttpData(fileUpload); } catch (ErrorDataEncoderException e) { throw Exceptions.propagate(e); } catch (IOException e) { throw Exceptions.propagate(new ErrorDataEncoderException(e)); } return this; } @Override public HttpClientForm files(String name, File[] files, String[] contentTypes) { for (int i = 0; i < files.length; i++) { file(name, files[i], contentTypes[i]); } return this; } @Override public HttpClientForm files(String name, File[] files, String[] contentTypes, boolean[] textFiles) { try { addBodyFileUploads(name, files, contentTypes, textFiles); } catch (ErrorDataEncoderException e) { throw Exceptions.propagate(e); } return this; } @Override public HttpClientForm encoding(EncoderMode mode) { this.newMode = Objects.requireNonNull(mode, "mode"); this.needNewEncoder = true; return this; } @Override public HttpClientForm multipart(boolean isMultipart) { this.needNewEncoder = isChunked() != isMultipart; this.newMultipart = isMultipart; return this; } @Override public HttpClientForm textFile(String name, File file) { textFile(name, file, null); return this; } @Override public HttpClientForm textFile(String name, File file, @Nullable String contentType) { try { addBodyFileUpload(name, file, contentType, true); } catch (ErrorDataEncoderException e) { throw Exceptions.propagate(e); } return this; } @Override public HttpClientForm textFile(String name, InputStream stream) { textFile(name, stream, null); return this; } @Override public HttpClientForm textFile(String name, InputStream stream, @Nullable String contentType) { Objects.requireNonNull(name, "name"); Objects.requireNonNull(stream, "stream"); try { String scontentType = contentType; if (contentType == null) { scontentType = DEFAULT_TEXT_CONTENT_TYPE; } FileUpload fileUpload = newFactory.createFileUpload(request, name, "", scontentType, null, newCharset, -1); fileUpload.setMaxSize(-1); fileUpload.setContent(stream); addBodyHttpData(fileUpload); } catch (ErrorDataEncoderException e) { throw Exceptions.propagate(e); } catch (IOException e) { throw Exceptions.propagate(new ErrorDataEncoderException(e)); } return this; } @Override public void run() { cleanFiles(); } final HttpClientFormEncoder applyChanges(HttpRequest request) { if (!needNewEncoder) { return this; } try { HttpClientFormEncoder encoder = new HttpClientFormEncoder(newFactory, request, newMultipart, newCharset, newMode); encoder.setBodyHttpDatas(getBodyListAttributes()); needNewEncoder = false; return encoder; } catch (ErrorDataEncoderException ee) { throw Exceptions.propagate(ee); } } static final Map percentEncodings = new HashMap<>(); static final String DEFAULT_BINARY_CONTENT_TYPE = "application/octet-stream"; static final String DEFAULT_TRANSFER_ENCODING = "binary"; static final String DEFAULT_TEXT_CONTENT_TYPE = "text/plain"; static { DiskFileUpload.deleteOnExitTemporaryFile = true; // should delete file // on exit (in normal // exit) DiskFileUpload.baseDirectory = null; // system temp directory DiskAttribute.deleteOnExitTemporaryFile = true; // should delete file on // exit (in normal exit) DiskAttribute.baseDirectory = null; // system temp directory percentEncodings.put(Pattern.compile("\\*"), "%2A"); percentEncodings.put(Pattern.compile("\\+"), "%20"); percentEncodings.put(Pattern.compile("%7E"), "~"); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy