This is an automated email from the ASF dual-hosted git repository.

albumenj pushed a commit to branch 3.3
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.3 by this push:
     new 6118aa55f2 Support more content types for Triple protocol (#13387)
6118aa55f2 is described below

commit 6118aa55f25978791dff55d3f1c30456b12a7335
Author: namelessssssssssss 
<100946116+namelesssssssss...@users.noreply.github.com>
AuthorDate: Sat Dec 16 11:36:22 2023 +0800

    Support more content types for Triple protocol (#13387)
    
    * Add more content type support for triple
    
    * Add more content type support for triple
    
    * Add tests & Bug fix
    
    * Code style fix
    
    * Code style fix
    
    * Code style fix
    
    * Code style fix
    
    * Code style fix
    
    * Set codec related dependencies to provided
    
    * Change CodecUtil to bean
    
    * Support Triple response encode by Accept header
    
    * Support Triple response encode by Accept header
    
    * Fix npe
    
    * Refactor response encode
    
    * Bug fix
    
    * Style fix
    
    * Bug fix & Add log
    
    * Style fix
    
    * Bug fix
    
    * Update ExceptionUtilsTest.java
    
    * Refactor
    
    * Fix code style
    
    * Refactor
    
    * Refactor
    
    * Code style fix
    
    * Refactor
    
    * Refactor
    
    * Code style optimize
    
    * Code style optimize
    
    * Refactor MultipartCodec
    
    * Add tests & Remove some dep
    
    * Remove commons_fileupload from bom
    
    * Simplify depedencies & clean up
    
    * Fix jaxb version
    
    * Enhance reliability for MultipartCodec & Add tests
    
    * Enhance reliability for MultipartCodec
    
    * Add test cases
    
    * Add test cases
    
    * Add test cases
    
    * Add test cases
    
    * Add test for xml safety
    
    * Add test for xml safety
    
    * Refactor CodecFactory
    
    * Refactor CodecFactory
    
    * Refactor CodecFactory
    
    * Add codec cache
    
    * Fix npe
    
    * Fix npe
    
    ---------
    
    Co-authored-by: nameless <x1544669...@gmail.com>
---
 dubbo-dependencies-bom/pom.xml                     |  12 +
 dubbo-distribution/dubbo-all/pom.xml               |   4 +-
 dubbo-remoting/dubbo-remoting-http12/pom.xml       |   9 +
 .../http12/AbstractServerHttpChannelObserver.java  |  18 +-
 .../dubbo/remoting/http12/HttpHeaderNames.java     |   4 +-
 .../apache/dubbo/remoting/http12/HttpHeaders.java  |   8 +
 .../remoting/http12/message/CodecMediaType.java    |  19 +-
 .../http12/message/DefaultListeningDecoder.java    |   8 +-
 .../remoting/http12/message/HttpMessageCodec.java  |  35 +-
 ...tpMessageCodec.java => HttpMessageDecoder.java} |  24 +-
 ...Factory.java => HttpMessageDecoderFactory.java} |  14 +-
 ...onCodecFactory.java => HttpMessageEncoder.java} |  20 +-
 ...Factory.java => HttpMessageEncoderFactory.java} |  19 +-
 .../dubbo/remoting/http12/message/MediaType.java   |   9 +
 .../remoting/http12/message/codec/CodecUtils.java  | 148 ++++++++
 .../http12/message/{ => codec}/JsonCodec.java      |  15 +-
 .../message/{ => codec}/JsonCodecFactory.java      |  18 +-
 .../http12/message/{ => codec}/JsonPbCodec.java    |  33 +-
 .../message/{ => codec}/JsonPbCodecFactory.java    |  32 +-
 .../http12/message/codec/MultipartDecoder.java     | 269 ++++++++++++++
 .../MultipartDecoderFactory.java}                  |  21 +-
 .../http12/message/codec/PlainTextCodec.java       |  78 ++++
 .../PlainTextCodecFactory.java}                    |  18 +-
 .../http12/message/codec/UrlEncodeFormCodec.java   | 128 +++++++
 .../message/codec/UrlEncodeFormCodecFactory.java   |  33 +-
 .../remoting/http12/message/codec/XmlCodec.java    |  74 ++++
 .../XmlCodecFactory.java}                          |  20 +-
 .../netty4/h1/NettyHttp1ConnectionHandler.java     |  30 +-
 ....dubbo.remoting.http12.message.HttpMessageCodec |   1 -
 ...remoting.http12.message.HttpMessageCodecFactory |   2 -
 ...moting.http12.message.HttpMessageDecoderFactory |   5 +
 ...moting.http12.message.HttpMessageEncoderFactory |   4 +
 .../http12/message/codec/CodeUtilsTest.java        |  71 ++++
 .../remoting/http12/message/codec/CodecTest.java   | 399 +++++++++++++++++++++
 .../dubbo/remoting/http12/message/codec/User.java} |  44 ++-
 .../http12/message/codec/XmlSafetyTest.java        | 115 ++++++
 .../src/test/resources/log4j2-test.xml             |  29 ++
 .../tri/h12/AbstractServerTransportListener.java   |  40 +--
 ...ressibleCodec.java => CompressibleEncoder.java} |  31 +-
 .../protocol/tri/h12/grpc/GrpcCompositeCodec.java  |  15 +-
 .../tri/h12/grpc/GrpcCompositeCodecFactory.java    |  14 +-
 .../rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java |   3 +-
 .../h12/grpc/GrpcHttp2ServerTransportListener.java |   7 +-
 .../tri/h12/grpc/ProtobufHttpMessageCodec.java     |   4 +-
 .../tri/h12/grpc/WrapperHttpMessageCodec.java      |   2 +-
 .../DefaultHttp11ServerTransportListener.java      |  17 +-
 .../http2/GenericHttp2ServerTransportListener.java |   7 +-
 .../tri/h12/http2/Http2ServerStreamObserver.java   |  17 +-
 ....dubbo.remoting.http12.message.HttpMessageCodec |   2 -
 ...remoting.http12.message.HttpMessageCodecFactory |   1 -
 ...moting.http12.message.HttpMessageDecoderFactory |   1 +
 ...moting.http12.message.HttpMessageEncoderFactory |   1 +
 52 files changed, 1581 insertions(+), 371 deletions(-)

diff --git a/dubbo-dependencies-bom/pom.xml b/dubbo-dependencies-bom/pom.xml
index 4121138d8e..384a14d0f3 100644
--- a/dubbo-dependencies-bom/pom.xml
+++ b/dubbo-dependencies-bom/pom.xml
@@ -207,6 +207,8 @@
     <palantirJavaFormat.version>2.38.0</palantirJavaFormat.version>
     <revision>3.3.0-beta.2-SNAPSHOT</revision>
     <open_feign_version>3.1.5</open_feign_version>
+    <jakarta.xml.bind-api.version>4.0.1</jakarta.xml.bind-api.version>
+    <jaxb-runtime.version>2.3.3-b02</jaxb-runtime.version>
   </properties>
 
   <dependencyManagement>
@@ -1073,6 +1075,16 @@
         <artifactId>spring-cloud-openfeign-core</artifactId>
         <version>${open_feign_version}</version>
       </dependency>
+      <dependency>
+        <groupId>jakarta.xml.bind</groupId>
+        <artifactId>jakarta.xml.bind-api</artifactId>
+        <version>${jakarta.xml.bind-api.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.glassfish.jaxb</groupId>
+        <artifactId>jaxb-runtime</artifactId>
+        <version>${jaxb-runtime.version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
diff --git a/dubbo-distribution/dubbo-all/pom.xml 
b/dubbo-distribution/dubbo-all/pom.xml
index 1faf586154..c92611d230 100644
--- a/dubbo-distribution/dubbo-all/pom.xml
+++ b/dubbo-distribution/dubbo-all/pom.xml
@@ -949,10 +949,10 @@
                   
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http.HttpBinder</resource>
                 </transformer>
                 <transformer 
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
-                  
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodec</resource>
+                  
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory</resource>
                 </transformer>
                 <transformer 
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
-                  
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory</resource>
+                  
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory</resource>
                 </transformer>
                 <transformer 
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                   
<resource>META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.h2.Http2ServerTransportListenerFactory</resource>
diff --git a/dubbo-remoting/dubbo-remoting-http12/pom.xml 
b/dubbo-remoting/dubbo-remoting-http12/pom.xml
index a59990aaae..5549f93993 100644
--- a/dubbo-remoting/dubbo-remoting-http12/pom.xml
+++ b/dubbo-remoting/dubbo-remoting-http12/pom.xml
@@ -60,5 +60,14 @@
       <artifactId>netty-codec-http2</artifactId>
     </dependency>
 
+    <dependency>
+      <groupId>javax.xml.bind</groupId>
+      <artifactId>jaxb-api</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.glassfish.jaxb</groupId>
+      <artifactId>jaxb-runtime</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java
index 65aaa6cd38..d13c4feeec 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/AbstractServerHttpChannelObserver.java
@@ -18,7 +18,7 @@ package org.apache.dubbo.remoting.http12;
 
 import org.apache.dubbo.remoting.http12.exception.EncodeException;
 import org.apache.dubbo.remoting.http12.exception.HttpStatusException;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
 
 public abstract class AbstractServerHttpChannelObserver implements 
CustomizableHttpChannelObserver<Object> {
 
@@ -32,18 +32,18 @@ public abstract class AbstractServerHttpChannelObserver 
implements CustomizableH
 
     private boolean headerSent;
 
-    private HttpMessageCodec httpMessageCodec;
+    private HttpMessageEncoder responseEncoder;
 
     public AbstractServerHttpChannelObserver(HttpChannel httpChannel) {
         this.httpChannel = httpChannel;
     }
 
-    public void setHttpMessageCodec(HttpMessageCodec httpMessageCodec) {
-        this.httpMessageCodec = httpMessageCodec;
+    public void setResponseEncoder(HttpMessageEncoder responseEncoder) {
+        this.responseEncoder = responseEncoder;
     }
 
-    protected HttpMessageCodec getHttpMessageCodec() {
-        return httpMessageCodec;
+    public HttpMessageEncoder getResponseEncoder() {
+        return responseEncoder;
     }
 
     @Override
@@ -77,7 +77,7 @@ public abstract class AbstractServerHttpChannelObserver 
implements CustomizableH
             }
             HttpOutputMessage outputMessage = encodeHttpOutputMessage(data);
             preOutputMessage(outputMessage);
-            this.httpMessageCodec.encode(outputMessage.getBody(), data);
+            this.responseEncoder.encode(outputMessage.getBody(), data);
             getHttpChannel().writeMessage(outputMessage);
             postOutputMessage(outputMessage);
         } catch (Throwable e) {
@@ -114,7 +114,7 @@ public abstract class AbstractServerHttpChannelObserver 
implements CustomizableH
             errorResponse.setMessage(throwable.getMessage());
             this.errorResponseCustomizer.accept(errorResponse, throwable);
             HttpOutputMessage httpOutputMessage = 
encodeHttpOutputMessage(errorResponse);
-            this.httpMessageCodec.encode(httpOutputMessage.getBody(), 
errorResponse);
+            this.responseEncoder.encode(httpOutputMessage.getBody(), 
errorResponse);
             getHttpChannel().writeMessage(httpOutputMessage);
         } catch (Throwable ex) {
             throwable = new EncodeException(ex);
@@ -140,7 +140,7 @@ public abstract class AbstractServerHttpChannelObserver 
implements CustomizableH
                 .headers()
                 .set(
                         HttpHeaderNames.CONTENT_TYPE.getName(),
-                        httpMessageCodec.contentType().getName());
+                        responseEncoder.mediaType().getName());
         this.headersCustomizer.accept(httpMetadata.headers());
         getHttpChannel().writeHeader(httpMetadata);
         this.headerSent = true;
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java
index 632dc0cdd0..65623ccacb 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaderNames.java
@@ -25,7 +25,9 @@ public enum HttpHeaderNames {
 
     TRANSFER_ENCODING("transfer-encoding"),
 
-    TE("te");
+    TE("te"),
+
+    ACCEPT("accept");
 
     private final String name;
 
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaders.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaders.java
index 24407ad9f2..6c42ab2b27 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaders.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/HttpHeaders.java
@@ -212,6 +212,14 @@ public class HttpHeaders implements Map<String, 
List<String>>, Serializable, Clo
         return result;
     }
 
+    public String getContentType() {
+        return getFirst(HttpHeaderNames.CONTENT_TYPE.getName());
+    }
+
+    public String getAccept() {
+        return getFirst(HttpHeaderNames.ACCEPT.getName());
+    }
+
     @Override
     public boolean equals(Object other) {
         return (this == other || this.targetMap.equals(other));
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/CodecMediaType.java
similarity index 68%
copy from 
dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/CodecMediaType.java
index 174a1756f4..20bca3dc14 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/CodecMediaType.java
@@ -14,22 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.protocol.tri.h12.grpc;
+package org.apache.dubbo.remoting.http12.message;
 
-public enum GrpcHeaderNames {
-    GRPC_STATUS("grpc-status"),
-    GRPC_MESSAGE("grpc-message"),
-    GRPC_ENCODING("grpc-encoding"),
-    GRPC_TIMEOUT("grpc-timeout"),
-    ;
+public interface CodecMediaType {
 
-    private final String name;
+    MediaType mediaType();
 
-    GrpcHeaderNames(String name) {
-        this.name = name;
-    }
-
-    public String getName() {
-        return name;
+    default boolean supports(String mediaType) {
+        return mediaType.startsWith(mediaType().getName());
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java
index dc57c7bf84..dfb02c63de 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java
@@ -20,14 +20,14 @@ import java.io.InputStream;
 
 public class DefaultListeningDecoder implements ListeningDecoder {
 
-    private final HttpMessageCodec httpMessageCodec;
+    private final HttpMessageDecoder httpMessageDecoder;
 
     private final Class<?>[] targetTypes;
 
     private Listener listener;
 
-    public DefaultListeningDecoder(HttpMessageCodec httpMessageCodec, 
Class<?>[] targetTypes) {
-        this.httpMessageCodec = httpMessageCodec;
+    public DefaultListeningDecoder(HttpMessageDecoder httpMessageDecoder, 
Class<?>[] targetTypes) {
+        this.httpMessageDecoder = httpMessageDecoder;
         this.targetTypes = targetTypes;
     }
 
@@ -38,7 +38,7 @@ public class DefaultListeningDecoder implements 
ListeningDecoder {
 
     @Override
     public void decode(InputStream inputStream) {
-        Object[] decode = this.httpMessageCodec.decode(inputStream, 
targetTypes);
+        Object[] decode = this.httpMessageDecoder.decode(inputStream, 
targetTypes);
         this.listener.onMessage(decode);
     }
 
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodec.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodec.java
index 35a23532c3..86b8ae00a8 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodec.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodec.java
@@ -16,40 +16,7 @@
  */
 package org.apache.dubbo.remoting.http12.message;
 
-import org.apache.dubbo.common.extension.ExtensionScope;
-import org.apache.dubbo.common.extension.SPI;
-import org.apache.dubbo.remoting.http12.exception.DecodeException;
-import org.apache.dubbo.remoting.http12.exception.EncodeException;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
 /**
  * for http body codec
  */
-@SPI(scope = ExtensionScope.FRAMEWORK)
-public interface HttpMessageCodec {
-
-    void encode(OutputStream outputStream, Object data) throws EncodeException;
-
-    default void encode(OutputStream outputStream, Object[] data) throws 
EncodeException {
-        // default encode first data
-        this.encode(outputStream, data == null || data.length == 0 ? null : 
data[0]);
-    }
-
-    Object decode(InputStream inputStream, Class<?> targetType) throws 
DecodeException;
-
-    default Object[] decode(InputStream inputStream, Class<?>[] targetTypes) 
throws DecodeException {
-        // default decode first target type
-        return new Object[] {
-            this.decode(inputStream, targetTypes == null || targetTypes.length 
== 0 ? null : targetTypes[0])
-        };
-    }
-
-    MediaType contentType();
-
-    default boolean support(String contentType) {
-        MediaType mediaType = this.contentType();
-        return mediaType.getName().startsWith(contentType);
-    }
-}
+public interface HttpMessageCodec extends HttpMessageEncoder, 
HttpMessageDecoder {}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodec.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoder.java
similarity index 62%
copy from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodec.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoder.java
index 35a23532c3..94e247a57d 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodec.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoder.java
@@ -16,26 +16,11 @@
  */
 package org.apache.dubbo.remoting.http12.message;
 
-import org.apache.dubbo.common.extension.ExtensionScope;
-import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.remoting.http12.exception.DecodeException;
-import org.apache.dubbo.remoting.http12.exception.EncodeException;
 
 import java.io.InputStream;
-import java.io.OutputStream;
 
-/**
- * for http body codec
- */
-@SPI(scope = ExtensionScope.FRAMEWORK)
-public interface HttpMessageCodec {
-
-    void encode(OutputStream outputStream, Object data) throws EncodeException;
-
-    default void encode(OutputStream outputStream, Object[] data) throws 
EncodeException {
-        // default encode first data
-        this.encode(outputStream, data == null || data.length == 0 ? null : 
data[0]);
-    }
+public interface HttpMessageDecoder extends CodecMediaType {
 
     Object decode(InputStream inputStream, Class<?> targetType) throws 
DecodeException;
 
@@ -46,10 +31,5 @@ public interface HttpMessageCodec {
         };
     }
 
-    MediaType contentType();
-
-    default boolean support(String contentType) {
-        MediaType mediaType = this.contentType();
-        return mediaType.getName().startsWith(contentType);
-    }
+    MediaType mediaType();
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoderFactory.java
similarity index 75%
rename from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodecFactory.java
rename to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoderFactory.java
index 9f8d3ac497..43ae1c632d 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageDecoderFactory.java
@@ -21,18 +21,8 @@ import org.apache.dubbo.common.extension.ExtensionScope;
 import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-/**
- * for http body codec
- */
 @SPI(scope = ExtensionScope.FRAMEWORK)
-public interface HttpMessageCodecFactory {
-
-    HttpMessageCodec createCodec(URL url, FrameworkModel frameworkModel);
-
-    MediaType contentType();
+public interface HttpMessageDecoderFactory extends CodecMediaType {
 
-    default boolean support(String contentType) {
-        MediaType mediaType = this.contentType();
-        return mediaType.getName().startsWith(contentType);
-    }
+    HttpMessageDecoder createCodec(URL url, FrameworkModel frameworkModel, 
String mediaType);
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoder.java
similarity index 63%
copy from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoder.java
index 64a7cd2f55..d4701ce501 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoder.java
@@ -16,22 +16,16 @@
  */
 package org.apache.dubbo.remoting.http12.message;
 
-import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.remoting.http12.exception.EncodeException;
 
-@Activate
-public class JsonCodecFactory implements HttpMessageCodecFactory {
+import java.io.OutputStream;
 
-    public static final String NAME = "json";
+public interface HttpMessageEncoder extends CodecMediaType {
 
-    @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        return new JsonCodec();
-    }
+    void encode(OutputStream outputStream, Object data) throws EncodeException;
 
-    @Override
-    public MediaType contentType() {
-        return MediaType.APPLICATION_JSON_VALUE;
+    default void encode(OutputStream outputStream, Object[] data) throws 
EncodeException {
+        // default encode first data
+        this.encode(outputStream, data == null || data.length == 0 ? null : 
data[0]);
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoderFactory.java
similarity index 69%
copy from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoderFactory.java
index 64a7cd2f55..4793eecf41 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/HttpMessageEncoderFactory.java
@@ -17,21 +17,12 @@
 package org.apache.dubbo.remoting.http12.message;
 
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-@Activate
-public class JsonCodecFactory implements HttpMessageCodecFactory {
+@SPI(scope = ExtensionScope.FRAMEWORK)
+public interface HttpMessageEncoderFactory extends CodecMediaType {
 
-    public static final String NAME = "json";
-
-    @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        return new JsonCodec();
-    }
-
-    @Override
-    public MediaType contentType() {
-        return MediaType.APPLICATION_JSON_VALUE;
-    }
+    HttpMessageEncoder createCodec(URL url, FrameworkModel frameworkModel, 
String mediaType);
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java
index 7703eeb50c..1f35951b87 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/MediaType.java
@@ -28,6 +28,15 @@ public class MediaType {
 
     public static final MediaType TEXT_EVENT_STREAM_VALUE = new 
MediaType("text", "event-stream");
 
+    public static final MediaType MULTIPART_FORM_DATA = new 
MediaType("multipart", "form-data");
+
+    public static final MediaType APPLICATION_X_WWW_FROM_URLENCODED =
+            new MediaType("application", "x-www-form-urlencoded");
+
+    public static final MediaType APPLICATION_XML = new 
MediaType("application", "xml");
+
+    public static final MediaType TEXT_PLAIN = new MediaType("text", "plain");
+
     private final String name;
 
     private final String type;
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java
new file mode 100644
index 0000000000..601d82c579
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/CodecUtils.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.http12.HttpHeaders;
+import 
org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import io.netty.handler.codec.CodecException;
+
+public class CodecUtils {
+
+    private final FrameworkModel frameworkModel;
+
+    private final List<HttpMessageDecoderFactory> decoders;
+
+    private final List<HttpMessageEncoderFactory> encoders;
+
+    private final Map<String, HttpMessageEncoderFactory> encoderCache;
+
+    private final Map<String, HttpMessageDecoderFactory> decoderCache;
+
+    public CodecUtils(FrameworkModel frameworkModel) {
+        this.encoderCache = new ConcurrentHashMap<>(1);
+        this.decoderCache = new ConcurrentHashMap<>(1);
+        this.frameworkModel = frameworkModel;
+        this.decoders = frameworkModel
+                .getExtensionLoader(HttpMessageDecoderFactory.class)
+                .getActivateExtensions();
+        this.encoders = frameworkModel
+                .getExtensionLoader(HttpMessageEncoderFactory.class)
+                .getActivateExtensions();
+        decoders.forEach(
+                decoderFactory -> 
decoderCache.put(decoderFactory.mediaType().getName(), decoderFactory));
+        encoders.forEach(
+                encoderFactory -> 
encoderCache.put(encoderFactory.mediaType().getName(), encoderFactory));
+    }
+
+    public HttpMessageDecoder determineHttpMessageDecoder(FrameworkModel 
frameworkModel, String contentType, URL url) {
+        return 
determineHttpMessageDecoderFactory(contentType).createCodec(url, 
frameworkModel, contentType);
+    }
+
+    public HttpMessageEncoder determineHttpMessageEncoder(FrameworkModel 
frameworkModel, HttpHeaders headers, URL url) {
+        String mediaType = getEncodeMediaType(headers);
+        return determineHttpMessageEncoderFactory(mediaType).createCodec(url, 
frameworkModel, mediaType);
+    }
+
+    public HttpMessageDecoderFactory determineHttpMessageDecoderFactory(String 
mediaType) {
+        HttpMessageDecoderFactory factory = 
decoderCache.computeIfAbsent(mediaType, k -> {
+            for (HttpMessageDecoderFactory decoderFactory : decoders) {
+                if (decoderFactory.supports(mediaType)) {
+                    return decoderFactory;
+                }
+            }
+            return new UnsupportedCodecFactory();
+        });
+        if (factory instanceof UnsupportedCodecFactory) {
+            throw new UnsupportedMediaTypeException(mediaType);
+        }
+        return factory;
+    }
+
+    public HttpMessageEncoderFactory determineHttpMessageEncoderFactory(String 
mediaType) {
+        HttpMessageEncoderFactory factory = 
encoderCache.computeIfAbsent(mediaType, k -> {
+            for (HttpMessageEncoderFactory encoderFactory : encoders) {
+                if (encoderFactory.supports(mediaType)) {
+                    return encoderFactory;
+                }
+            }
+            return new UnsupportedCodecFactory();
+        });
+        if (factory instanceof UnsupportedCodecFactory) {
+            throw new UnsupportedMediaTypeException(mediaType);
+        }
+        return factory;
+    }
+
+    public List<HttpMessageDecoderFactory> getDecoders() {
+        return decoders;
+    }
+
+    public List<HttpMessageEncoderFactory> getEncoders() {
+        return encoders;
+    }
+
+    static class UnsupportedCodecFactory implements HttpMessageEncoderFactory, 
HttpMessageDecoderFactory {
+        @Override
+        public MediaType mediaType() {
+            throw new CodecException();
+        }
+
+        @Override
+        public boolean supports(String mediaType) {
+            throw new CodecException();
+        }
+
+        @Override
+        public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
+            throw new CodecException();
+        }
+    }
+
+    public static String getEncodeMediaType(HttpHeaders headers) {
+        String mediaType = headers.getAccept();
+        if (mediaType == null) {
+            mediaType = headers.getContentType();
+        }
+        return mediaType;
+    }
+
+    public static ByteArrayOutputStream toByteArrayStream(InputStream in) 
throws IOException {
+        ByteArrayOutputStream result = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int length;
+        while ((length = in.read(buffer)) != -1) {
+            result.write(buffer, 0, length);
+        }
+        return result;
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodec.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodec.java
similarity index 93%
rename from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodec.java
rename to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodec.java
index 329707a5d5..da38387df0 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodec.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodec.java
@@ -14,12 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
-import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.common.utils.JsonUtils;
 import org.apache.dubbo.remoting.http12.exception.DecodeException;
 import org.apache.dubbo.remoting.http12.exception.EncodeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.MediaType;
 
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -29,20 +30,13 @@ import java.util.List;
 
 import com.alibaba.fastjson2.JSONObject;
 
-/**
- * body is json
- */
-@Activate
 public class JsonCodec implements HttpMessageCodec {
 
-    public static final HttpMessageCodec INSTANCE = new JsonCodec();
-
     @Override
-    public MediaType contentType() {
+    public MediaType mediaType() {
         return MediaType.APPLICATION_JSON_VALUE;
     }
 
-    @Override
     public void encode(OutputStream outputStream, Object unSerializedBody) 
throws EncodeException {
         try {
             try {
@@ -56,7 +50,6 @@ public class JsonCodec implements HttpMessageCodec {
         }
     }
 
-    @Override
     public void encode(OutputStream outputStream, Object[] data) throws 
EncodeException {
         try {
             try {
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodecFactory.java
similarity index 64%
copy from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodecFactory.java
index 64a7cd2f55..25fdcdb3e6 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonCodecFactory.java
@@ -14,24 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
+import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-@Activate
-public class JsonCodecFactory implements HttpMessageCodecFactory {
+public class JsonCodecFactory implements HttpMessageEncoderFactory, 
HttpMessageDecoderFactory {
 
-    public static final String NAME = "json";
+    private final JsonCodec instance = new JsonCodec();
 
     @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        return new JsonCodec();
+    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
+        return instance;
     }
 
     @Override
-    public MediaType contentType() {
+    public MediaType mediaType() {
         return MediaType.APPLICATION_JSON_VALUE;
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonPbCodec.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java
similarity index 79%
rename from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonPbCodec.java
rename to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java
index 6b4a6ff5b8..caac2c3fb4 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonPbCodec.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodec.java
@@ -14,13 +14,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
-import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.common.utils.ClassUtils;
 import org.apache.dubbo.common.utils.MethodUtils;
 import org.apache.dubbo.remoting.http12.exception.DecodeException;
 import org.apache.dubbo.remoting.http12.exception.EncodeException;
+import org.apache.dubbo.remoting.http12.message.MediaType;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -30,25 +29,11 @@ import java.nio.charset.StandardCharsets;
 import com.google.protobuf.Message;
 import com.google.protobuf.util.JsonFormat;
 
-@Activate
-public class JsonPbCodec implements HttpMessageCodec {
-
-    private HttpMessageCodec jsonCodec;
-
-    public void setJsonCodec(HttpMessageCodec jsonCodec) {
-        this.jsonCodec = jsonCodec;
-    }
-
-    @Override
-    public MediaType contentType() {
-        return jsonCodec.contentType();
-    }
+public class JsonPbCodec extends JsonCodec {
 
     @Override
-    public boolean support(String contentType) {
-        return HttpMessageCodec.super.support(contentType)
-                && ClassUtils.isPresent(
-                        "com.google.protobuf.Message", 
getClass().getClassLoader());
+    public MediaType mediaType() {
+        return MediaType.APPLICATION_JSON_VALUE;
     }
 
     @Override
@@ -62,12 +47,12 @@ public class JsonPbCodec implements HttpMessageCodec {
         } catch (IOException e) {
             throw new EncodeException(e);
         }
-        jsonCodec.encode(outputStream, unSerializedBody);
+        super.encode(outputStream, unSerializedBody);
     }
 
     @Override
     public void encode(OutputStream outputStream, Object[] data) throws 
EncodeException {
-        jsonCodec.encode(outputStream, data);
+        super.encode(outputStream, data);
     }
 
     @Override
@@ -88,7 +73,7 @@ public class JsonPbCodec implements HttpMessageCodec {
         } catch (Throwable e) {
             throw new DecodeException(e);
         }
-        return jsonCodec.decode(body, targetType);
+        return super.decode(body, targetType);
     }
 
     @Override
@@ -101,7 +86,7 @@ public class JsonPbCodec implements HttpMessageCodec {
         } catch (Throwable e) {
             throw new DecodeException(e);
         }
-        return jsonCodec.decode(dataInputStream, targetTypes);
+        return super.decode(dataInputStream, targetTypes);
     }
 
     private static boolean isProtobuf(Class<?> targetType) {
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonPbCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java
similarity index 56%
rename from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonPbCodecFactory.java
rename to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java
index bc82ce9ca0..e4b01f06dc 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonPbCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/JsonPbCodecFactory.java
@@ -14,36 +14,28 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.Activate;
-import org.apache.dubbo.common.utils.ClassUtils;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
+import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-@Activate(order = -100)
-public class JsonPbCodecFactory implements HttpMessageCodecFactory {
+@Activate
+public class JsonPbCodecFactory implements HttpMessageEncoderFactory, 
HttpMessageDecoderFactory {
 
-    @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        HttpMessageCodec codec = frameworkModel
-                .getExtensionLoader(HttpMessageCodecFactory.class)
-                .getExtension(JsonCodecFactory.NAME)
-                .createCodec(url, frameworkModel);
-        JsonPbCodec jsonPbCodec = new JsonPbCodec();
-        jsonPbCodec.setJsonCodec(codec);
-        return jsonPbCodec;
-    }
+    private final JsonPbCodec instance = new JsonPbCodec();
 
     @Override
-    public MediaType contentType() {
-        return MediaType.APPLICATION_JSON_VALUE;
+    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
+        return instance;
     }
 
     @Override
-    public boolean support(String contentType) {
-        return HttpMessageCodecFactory.super.support(contentType)
-                && ClassUtils.isPresent(
-                        "com.google.protobuf.Message", 
getClass().getClassLoader());
+    public MediaType mediaType() {
+        return MediaType.APPLICATION_JSON_VALUE;
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoder.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoder.java
new file mode 100644
index 0000000000..560e5db1a7
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoder.java
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.remoting.http12.HttpHeaderNames;
+import org.apache.dubbo.remoting.http12.HttpHeaders;
+import org.apache.dubbo.remoting.http12.exception.DecodeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+public class MultipartDecoder implements HttpMessageDecoder {
+
+    private final URL url;
+
+    private final FrameworkModel frameworkModel;
+
+    private final String headerContentType;
+
+    private final CodecUtils codecUtils;
+
+    private static final String CRLF = "\r\n";
+
+    public MultipartDecoder(URL url, FrameworkModel frameworkModel, String 
contentType, CodecUtils codecUtils) {
+        this.url = url;
+        this.frameworkModel = frameworkModel;
+        this.headerContentType = contentType;
+        this.codecUtils = codecUtils;
+    }
+
+    @Override
+    public Object decode(InputStream inputStream, Class<?> targetType) throws 
DecodeException {
+        Object[] res = decode(inputStream, new Class[] {targetType});
+        return res.length > 1 ? res : res[0];
+    }
+
+    @Override
+    public Object[] decode(InputStream inputStream, Class<?>[] targetTypes) 
throws DecodeException {
+        try {
+            List<Part> parts = transferToParts(inputStream, headerContentType);
+            if (parts.size() != targetTypes.length) {
+                throw new DecodeException("The number of method parameters and 
multipart request bodies are different");
+            }
+            Object[] res = new Object[parts.size()];
+
+            for (int i = 0; i < parts.size(); i++) {
+                Part part = parts.get(i);
+
+                if (Byte[].class.equals(targetTypes[i]) || 
byte[].class.equals(targetTypes[i])) {
+                    res[i] = part.content;
+                    continue;
+                }
+                res[i] = codecUtils
+                        .determineHttpMessageDecoder(frameworkModel, 
part.headers.getContentType(), url)
+                        .decode(new ByteArrayInputStream(part.content), 
targetTypes[i]);
+            }
+            return res;
+        } catch (IOException ioException) {
+            throw new DecodeException("Decode multipart body failed:" + 
ioException.getMessage());
+        }
+    }
+
+    private List<Part> transferToParts(InputStream inputStream, String 
contentType) throws IOException {
+        String boundary = getBoundaryFromContentType(contentType);
+        if (StringUtils.isEmpty(boundary)) {
+            throw new DecodeException("Invalid boundary in Content-Type: " + 
contentType);
+        }
+
+        final String delimiter = "--" + boundary;
+
+        List<Part> parts = new ArrayList<>();
+        boolean endOfStream = false;
+
+        while (!endOfStream) {
+            ByteArrayOutputStream partData = new ByteArrayOutputStream();
+            HttpHeaders headers = new HttpHeaders();
+
+            endOfStream = readPart(inputStream, delimiter, headers, partData);
+
+            if (partData.size() > 0) {
+                parts.add(new Part(partData.toByteArray(), headers));
+            }
+        }
+
+        return parts;
+    }
+
+    private String getBoundaryFromContentType(String contentType) {
+        String[] parts = contentType.split(";");
+        for (String part : parts) {
+            part = part.trim();
+            if (part.startsWith("boundary=")) {
+                return part.substring("boundary=".length()).trim();
+            }
+        }
+        return null;
+    }
+
+    private boolean readPart(
+            InputStream inputStream, String delimiter, HttpHeaders headers, 
ByteArrayOutputStream partData)
+            throws IOException {
+        // read and parse headers
+        if (readHeaders(inputStream, headers, delimiter)) {
+            // end of stream
+            return true;
+        }
+        return readBody(inputStream, delimiter, partData);
+    }
+
+    private boolean readHeaders(InputStream inputStream, HttpHeaders 
httpHeaders, String delimiter) throws IOException {
+
+        StringBuilder fullHeaderBuilder = new StringBuilder();
+        String fullHeader = null;
+        byte[] buffer = new byte[128];
+        int len;
+        boolean headerEnd = false;
+        boolean streamEnd = true;
+        final String endOfHeaderSign = CRLF + CRLF;
+
+        byte[] delimiterBuffer = new byte[delimiter.length()];
+        if (inputStream.read(delimiterBuffer) == -1) {
+            return true;
+        }
+        String readDelimiter = new String(delimiterBuffer, 
StandardCharsets.US_ASCII);
+        if (!Objects.equals(readDelimiter, delimiter)) {
+            throw new DecodeException("Multipart body boundary are different 
from header");
+        }
+        while (!headerEnd) {
+
+            inputStream.mark(Integer.MAX_VALUE);
+
+            len = inputStream.read(buffer);
+            if (len == -1) {
+                break;
+            }
+
+            // read to 2*CRLF (end of header)
+            String currentString = new String(buffer, 0, len, 
StandardCharsets.UTF_8);
+            fullHeaderBuilder.append(currentString);
+
+            // check if currentString contains CRLF
+            int endIndex;
+            if ((endIndex = fullHeaderBuilder.indexOf(endOfHeaderSign)) != -1) 
{
+                // make stream reset to body start of current part
+                inputStream.reset();
+                if (inputStream.skip(endIndex + endOfHeaderSign.length()) == 
endIndex + endOfHeaderSign.length()) {
+                    streamEnd = false;
+                }
+                headerEnd = true;
+                fullHeader = fullHeaderBuilder.substring(delimiter.length(), 
endIndex);
+            }
+        }
+        if (streamEnd && !headerEnd) {
+            throw new DecodeException("Broken request: cannot found multipart 
body header end");
+        }
+
+        parseHeaderLine(httpHeaders, fullHeader.split(CRLF));
+
+        if (httpHeaders.getContentType() == null) {
+            httpHeaders.put(HttpHeaderNames.CONTENT_TYPE.getName(), 
Collections.singletonList("text/plain"));
+        }
+
+        return streamEnd;
+    }
+
+    private void parseHeaderLine(HttpHeaders headers, String[] headerLines) {
+        for (String headerLine : headerLines) {
+            int colonIndex = headerLine.indexOf(':');
+            if (colonIndex != -1) {
+                String name = headerLine.substring(0, colonIndex).trim();
+                String value = headerLine.substring(colonIndex + 1).trim();
+                headers.put(name, Collections.singletonList(value));
+            }
+        }
+    }
+
+    private boolean readBody(InputStream inputStream, String delimiter, 
ByteArrayOutputStream partData)
+            throws IOException {
+        byte[] buffer = new byte[256];
+        int len;
+
+        while (true) {
+            inputStream.mark(Integer.MAX_VALUE);
+            len = inputStream.read(buffer);
+            if (len == -1) {
+                return true;
+            }
+            String currentString = new String(buffer, 0, len, 
StandardCharsets.US_ASCII);
+            if (currentString.contains(delimiter)) {
+                int indexOfDelimiter = currentString.indexOf(delimiter);
+
+                // skip the CRLF of data tail
+                byte[] toWrite = new byte[indexOfDelimiter - 2];
+                System.arraycopy(buffer, 0, toWrite, 0, indexOfDelimiter - 2);
+                partData.write(toWrite);
+
+                // check end delimiter (--\r\n) to determine if this part is 
the last body part
+                // for compatibility with non-standard clients, we won't check 
the last CRLF
+                if (currentString.length() > indexOfDelimiter + 
delimiter.length() + 1
+                        && currentString.charAt(indexOfDelimiter + 
delimiter.length()) == '-'
+                        && currentString.charAt(indexOfDelimiter + 
delimiter.length() + 1) == '-') {
+                    return true;
+                }
+
+                // read from stream to check end delimiter
+                else if (currentString.length() <= indexOfDelimiter + 
delimiter.length() + 1) {
+                    byte[] endDelimiter = new byte[2];
+                    if (inputStream.read(endDelimiter) != 2) {
+                        throw new DecodeException("Boundary end is 
incomplete");
+                    }
+                    if (endDelimiter[0] == '-' && endDelimiter[1] == '-') {
+                        return true;
+                    } else {
+                        inputStream.reset();
+                        inputStream.skip(toWrite.length + 2);
+                    }
+                } else {
+                    inputStream.reset();
+                    inputStream.skip(toWrite.length + 2);
+                }
+                return false;
+            }
+            partData.write(buffer, 0, len);
+        }
+    }
+
+    @Override
+    public MediaType mediaType() {
+        return MediaType.MULTIPART_FORM_DATA;
+    }
+
+    private static class Part {
+
+        private final byte[] content;
+
+        private final HttpHeaders headers;
+
+        public Part(byte[] content, HttpHeaders headers) {
+            this.content = content;
+            this.headers = headers;
+        }
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoderFactory.java
similarity index 57%
copy from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoderFactory.java
index 64a7cd2f55..2e55e0129f 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/MultipartDecoderFactory.java
@@ -14,24 +14,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 @Activate
-public class JsonCodecFactory implements HttpMessageCodecFactory {
+public class MultipartDecoderFactory implements HttpMessageDecoderFactory {
 
-    public static final String NAME = "json";
+    private CodecUtils codecUtils;
+
+    public void setCodecUtils(CodecUtils codecUtils) {
+        this.codecUtils = codecUtils;
+    }
 
     @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        return new JsonCodec();
+    public HttpMessageDecoder createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
+        return new MultipartDecoder(url, frameworkModel, mediaType, 
codecUtils);
     }
 
     @Override
-    public MediaType contentType() {
-        return MediaType.APPLICATION_JSON_VALUE;
+    public MediaType mediaType() {
+        return MediaType.MULTIPART_FORM_DATA;
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java
new file mode 100644
index 0000000000..3516c749dc
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodec.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import org.apache.dubbo.remoting.http12.exception.DecodeException;
+import org.apache.dubbo.remoting.http12.exception.EncodeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+public class PlainTextCodec implements HttpMessageCodec {
+
+    private final String contentType;
+
+    public PlainTextCodec(String contentType) {
+        this.contentType = contentType;
+    }
+
+    @Override
+    public void encode(OutputStream outputStream, Object data) throws 
EncodeException {
+        if (!(data instanceof String)) {
+            throw new EncodeException("PlainText media-type only supports 
String as return type.");
+        }
+        try {
+            outputStream.write(((String) data).getBytes());
+        } catch (IOException e) {
+            throw new EncodeException(e);
+        }
+    }
+
+    @Override
+    public MediaType mediaType() {
+        return MediaType.TEXT_PLAIN;
+    }
+
+    @Override
+    public Object decode(InputStream inputStream, Class<?> targetType) throws 
DecodeException {
+        try {
+            if (!String.class.equals(targetType)) {
+                throw new DecodeException("Plain text content only supports 
String as method param.");
+            }
+            Charset charset;
+            if (contentType.contains("charset=")) {
+                try {
+                    charset = 
Charset.forName(contentType.substring(contentType.indexOf("charset=") + 8));
+                } catch (Exception e) {
+                    throw new DecodeException("Unsupported charset:" + 
e.getMessage());
+                }
+                if (!charset.equals(StandardCharsets.UTF_8) && 
!charset.equals(StandardCharsets.US_ASCII)) {
+                    String origin = 
CodecUtils.toByteArrayStream(inputStream).toString(charset.name());
+                    return new String(origin.getBytes(StandardCharsets.UTF_8), 
StandardCharsets.UTF_8);
+                }
+            }
+            return 
CodecUtils.toByteArrayStream(inputStream).toString(StandardCharsets.UTF_8.name());
+        } catch (Exception e) {
+            throw new DecodeException(e);
+        }
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodecFactory.java
similarity index 64%
copy from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodecFactory.java
index 64a7cd2f55..b8c400a7a7 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/PlainTextCodecFactory.java
@@ -14,24 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
+import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 @Activate
-public class JsonCodecFactory implements HttpMessageCodecFactory {
-
-    public static final String NAME = "json";
+public class PlainTextCodecFactory implements HttpMessageEncoderFactory, 
HttpMessageDecoderFactory {
 
     @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        return new JsonCodec();
+    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
+        return new PlainTextCodec(mediaType);
     }
 
     @Override
-    public MediaType contentType() {
-        return MediaType.APPLICATION_JSON_VALUE;
+    public MediaType mediaType() {
+        return MediaType.TEXT_PLAIN;
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodec.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodec.java
new file mode 100644
index 0000000000..2e16b6d382
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodec.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import org.apache.dubbo.common.convert.ConverterUtil;
+import org.apache.dubbo.remoting.http12.exception.DecodeException;
+import org.apache.dubbo.remoting.http12.exception.EncodeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class UrlEncodeFormCodec implements HttpMessageCodec {
+
+    private final ConverterUtil converterUtil;
+
+    public UrlEncodeFormCodec(ConverterUtil converterUtil) {
+        this.converterUtil = converterUtil;
+    }
+
+    @Override
+    public void encode(OutputStream outputStream, Object data) throws 
EncodeException {
+        try {
+            if (data instanceof String) {
+                outputStream.write(((String) data).getBytes());
+            } else if (data instanceof Map) {
+                StringBuilder toWrite = new StringBuilder();
+                for (Map.Entry<?, ?> e : ((Map<?, ?>) data).entrySet()) {
+                    String k = e.getKey().toString();
+                    String v = e.getValue().toString();
+                    toWrite.append(k).append("=").append(v).append("&");
+                }
+                if (toWrite.length() > 1) {
+                    outputStream.write(
+                            toWrite.substring(0, toWrite.length() - 
1).getBytes());
+                }
+            } else {
+                throw new EncodeException("UrlEncodeFrom media-type only 
supports String or Map as return type.");
+            }
+        } catch (Exception e) {
+            throw new EncodeException(e);
+        }
+    }
+
+    @Override
+    public Object decode(InputStream inputStream, Class<?> targetType) throws 
DecodeException {
+        Object[] res = decode(inputStream, new Class[] {targetType});
+        return res.length > 1 ? res : res[0];
+    }
+
+    @Override
+    public Object[] decode(InputStream inputStream, Class<?>[] targetTypes) 
throws DecodeException {
+        try {
+            boolean toMap;
+            // key=value&key2=value2 -> method(map<keys,values>)
+            if (targetTypes.length == 1 && 
targetTypes[0].isAssignableFrom(HashMap.class)) {
+                toMap = true;
+            }
+            // key=value&key2=value2 -> method(value,value2)
+            else if (Arrays.stream(targetTypes)
+                    .allMatch(clz -> String.class.isAssignableFrom(clz) || 
Number.class.isAssignableFrom(clz))) {
+                toMap = false;
+            } else {
+                throw new DecodeException(
+                        "For x-www-form-urlencoded MIME type, please use 
Map/String/base-types as method param.");
+            }
+            String decoded = URLDecoder.decode(
+                            
CodecUtils.toByteArrayStream(inputStream).toString(), 
StandardCharsets.UTF_8.name())
+                    .trim();
+            Map<String, Object> res = toMap(decoded, targetTypes, toMap);
+            if (toMap) {
+                return new Object[] {res};
+            } else {
+                return res.values().toArray();
+            }
+        } catch (Exception e) {
+            throw new DecodeException(e);
+        }
+    }
+
+    private Map<String, Object> toMap(String formString, Class<?>[] 
targetTypes, boolean toMap) {
+        Map<String, Object> res = new HashMap<>(1);
+        // key1=val1&key2=&key3=&key4=val4
+        String[] parts = formString.split("&");
+        for (int i = 0; i < parts.length; i++) {
+            String pair = parts[i];
+            int index = pair.indexOf("=");
+            if (index < 1) {
+                throw new DecodeException("Broken request:" + formString);
+            }
+            String key = pair.substring(0, index);
+            String val = (index == pair.length() - 1) ? "" : 
pair.substring(index + 1);
+            res.put(
+                    key,
+                    toMap || targetTypes[i].equals(String.class)
+                            // method params are Map or String, use plain text 
as value
+                            ? val
+                            // try convert to target types
+                            : converterUtil.convertIfPossible(val, 
targetTypes[i]));
+        }
+        return res;
+    }
+
+    @Override
+    public MediaType mediaType() {
+        return MediaType.APPLICATION_X_WWW_FROM_URLENCODED;
+    }
+}
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodecFactory.java
similarity index 52%
copy from 
dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodecFactory.java
index 792fde774d..0b657ffd09 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/UrlEncodeFormCodecFactory.java
@@ -14,37 +14,34 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.rpc.protocol.tri.h12.grpc;
+package org.apache.dubbo.remoting.http12.message.codec;
 
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.common.convert.ConverterUtil;
 import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
 import org.apache.dubbo.remoting.http12.message.MediaType;
-import org.apache.dubbo.remoting.utils.UrlUtils;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-@Activate
-public class GrpcCompositeCodecFactory implements HttpMessageCodecFactory {
+public class UrlEncodeFormCodecFactory implements HttpMessageEncoderFactory, 
HttpMessageDecoderFactory {
 
-    private static final MediaType MEDIA_TYPE = new MediaType("application", 
"grpc");
+    private final ConverterUtil converterUtil;
 
-    @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        final String serializeName = UrlUtils.serializationOrDefault(url);
-        WrapperHttpMessageCodec wrapperHttpMessageCodec = new 
WrapperHttpMessageCodec(url, frameworkModel);
-        wrapperHttpMessageCodec.setSerializeType(serializeName);
-        ProtobufHttpMessageCodec protobufHttpMessageCodec = new 
ProtobufHttpMessageCodec();
-        return new GrpcCompositeCodec(protobufHttpMessageCodec, 
wrapperHttpMessageCodec);
+    private final UrlEncodeFormCodec instance;
+
+    public UrlEncodeFormCodecFactory(FrameworkModel frameworkModel) {
+        this.converterUtil = 
frameworkModel.getBeanFactory().getBean(ConverterUtil.class);
+        this.instance = new UrlEncodeFormCodec(this.converterUtil);
     }
 
     @Override
-    public MediaType contentType() {
-        return MEDIA_TYPE;
+    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
+        return instance;
     }
 
     @Override
-    public boolean support(String contentType) {
-        return contentType.startsWith(MEDIA_TYPE.getName());
+    public MediaType mediaType() {
+        return MediaType.APPLICATION_X_WWW_FROM_URLENCODED;
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodec.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodec.java
new file mode 100644
index 0000000000..9d2bd8f020
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodec.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import org.apache.dubbo.remoting.http12.exception.DecodeException;
+import org.apache.dubbo.remoting.http12.exception.EncodeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.sax.SAXSource;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+
+import org.xml.sax.InputSource;
+
+public class XmlCodec implements HttpMessageCodec {
+
+    @Override
+    public void encode(OutputStream outputStream, Object data) throws 
EncodeException {
+        try {
+            Marshaller marshaller = 
JAXBContext.newInstance(data.getClass()).createMarshaller();
+            marshaller.marshal(data, outputStream);
+        } catch (Exception e) {
+            throw new EncodeException(e);
+        }
+    }
+
+    @Override
+    public Object decode(InputStream inputStream, Class<?> targetType) throws 
DecodeException {
+        try {
+            SAXParserFactory spf = SAXParserFactory.newInstance();
+            
spf.setFeature("http://xml.org/sax/features/external-general-entities";, false);
+            
spf.setFeature("http://xml.org/sax/features/external-parameter-entities";, 
false);
+            
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd";,
 false);
+
+            // Do unmarshall operation
+            Source xmlSource = new SAXSource(
+                    spf.newSAXParser().getXMLReader(),
+                    new InputSource(new StringReader(
+                            
CodecUtils.toByteArrayStream(inputStream).toString())));
+            JAXBContext context = JAXBContext.newInstance(targetType);
+            Unmarshaller unmarshaller = context.createUnmarshaller();
+            return unmarshaller.unmarshal(xmlSource);
+        } catch (Exception e) {
+            throw new DecodeException(e);
+        }
+    }
+
+    @Override
+    public MediaType mediaType() {
+        return MediaType.APPLICATION_XML;
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodecFactory.java
similarity index 61%
rename from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
rename to 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodecFactory.java
index 64a7cd2f55..3738c45cfb 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/JsonCodecFactory.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/codec/XmlCodecFactory.java
@@ -14,24 +14,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
 import org.apache.dubbo.common.URL;
-import org.apache.dubbo.common.extension.Activate;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
+import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-@Activate
-public class JsonCodecFactory implements HttpMessageCodecFactory {
+public class XmlCodecFactory implements HttpMessageEncoderFactory, 
HttpMessageDecoderFactory {
 
-    public static final String NAME = "json";
+    private final HttpMessageCodec instance = new XmlCodec();
 
     @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
-        return new JsonCodec();
+    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
+        return instance;
     }
 
     @Override
-    public MediaType contentType() {
-        return MediaType.APPLICATION_JSON_VALUE;
+    public MediaType mediaType() {
+        return MediaType.APPLICATION_XML;
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java
index 77d7724853..c43fa7cab6 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/netty4/h1/NettyHttp1ConnectionHandler.java
@@ -27,10 +27,9 @@ import org.apache.dubbo.remoting.http12.h1.Http1Request;
 import org.apache.dubbo.remoting.http12.h1.Http1ServerChannelObserver;
 import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener;
 import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListenerFactory;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory;
+import org.apache.dubbo.remoting.http12.message.codec.CodecUtils;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-import java.util.List;
 import java.util.concurrent.Executor;
 
 import io.netty.channel.ChannelHandlerContext;
@@ -46,6 +45,8 @@ public class NettyHttp1ConnectionHandler extends 
SimpleChannelInboundHandler<Htt
 
     private final Executor executor;
 
+    private final CodecUtils codecUtils;
+
     private Http1ServerChannelObserver errorResponseObserver;
 
     public NettyHttp1ConnectionHandler(URL url, FrameworkModel frameworkModel) 
{
@@ -55,6 +56,7 @@ public class NettyHttp1ConnectionHandler extends 
SimpleChannelInboundHandler<Htt
                 .getExtensionLoader(ThreadPool.class)
                 .getAdaptiveExtension()
                 .getExecutor(url);
+        this.codecUtils = 
frameworkModel.getBeanFactory().getBean(CodecUtils.class);
     }
 
     public NettyHttp1ConnectionHandler(
@@ -67,6 +69,7 @@ public class NettyHttp1ConnectionHandler extends 
SimpleChannelInboundHandler<Htt
                 .getExtensionLoader(ThreadPool.class)
                 .getAdaptiveExtension()
                 .getExecutor(url);
+        this.codecUtils = 
frameworkModel.getBeanFactory().getBean(CodecUtils.class);
         this.http1ServerTransportListenerFactory = 
http1ServerTransportListenerFactory;
     }
 
@@ -78,6 +81,7 @@ public class NettyHttp1ConnectionHandler extends 
SimpleChannelInboundHandler<Htt
     protected void channelRead0(ChannelHandlerContext ctx, Http1Request 
http1Request) {
         // process h1 request
         Http1ServerTransportListener http1TransportListener = 
initTransportListenerIfNecessary(ctx, http1Request);
+        initErrorResponseObserver(ctx, http1Request);
         executor.execute(() -> {
             try {
                 http1TransportListener.onMetadata(http1Request);
@@ -102,24 +106,14 @@ public class NettyHttp1ConnectionHandler extends 
SimpleChannelInboundHandler<Htt
         if (!StringUtils.hasText(contentType)) {
             throw new UnsupportedMediaTypeException(contentType);
         }
-        HttpMessageCodecFactory codecFactory = findSuitableCodec(
-                contentType,
-                
frameworkModel.getExtensionLoader(HttpMessageCodecFactory.class).getActivateExtensions());
-        if (codecFactory == null) {
-            throw new UnsupportedMediaTypeException(contentType);
-        }
-        this.errorResponseObserver = new Http1ServerChannelObserver(new 
NettyHttp1Channel(ctx.channel()));
-        
this.errorResponseObserver.setHttpMessageCodec(codecFactory.createCodec(url, 
frameworkModel));
+        // check ContentType
+        codecUtils.determineHttpMessageDecoder(frameworkModel, 
headers.getContentType(), url);
         return http1TransportListener;
     }
 
-    private static HttpMessageCodecFactory findSuitableCodec(
-            String contentType, List<HttpMessageCodecFactory> candidates) {
-        for (HttpMessageCodecFactory factory : candidates) {
-            if (factory.support(contentType)) {
-                return factory;
-            }
-        }
-        return null;
+    private void initErrorResponseObserver(ChannelHandlerContext ctx, 
Http1Request request) {
+        this.errorResponseObserver = new Http1ServerChannelObserver(new 
NettyHttp1Channel(ctx.channel()));
+        this.errorResponseObserver.setResponseEncoder(
+                codecUtils.determineHttpMessageEncoder(frameworkModel, 
request.headers(), url));
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodec
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodec
deleted file mode 100644
index 10f9ef3dd9..0000000000
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodec
+++ /dev/null
@@ -1 +0,0 @@
-json=org.apache.dubbo.remoting.http12.message.JsonCodec
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory
deleted file mode 100644
index 0fcf5fb19a..0000000000
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory
+++ /dev/null
@@ -1,2 +0,0 @@
-json=org.apache.dubbo.remoting.http12.message.JsonCodecFactory
-jsonpb=org.apache.dubbo.remoting.http12.message.JsonPbCodecFactory
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
new file mode 100644
index 0000000000..5637aa5975
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
@@ -0,0 +1,5 @@
+jsonpb=org.apache.dubbo.remoting.http12.message.codec.JsonPbCodecFactory
+multipart=org.apache.dubbo.remoting.http12.message.codec.MultipartDecoderFactory
+plaintext=org.apache.dubbo.remoting.http12.message.codec.PlainTextCodecFactory
+xml=org.apache.dubbo.remoting.http12.message.codec.XmlCodecFactory
+urlencoded=org.apache.dubbo.remoting.http12.message.codec.UrlEncodeFormCodecFactory
\ No newline at end of file
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
 
b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
new file mode 100644
index 0000000000..2243b9e032
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
@@ -0,0 +1,4 @@
+jsonpb=org.apache.dubbo.remoting.http12.message.codec.JsonPbCodecFactory
+plaintext=org.apache.dubbo.remoting.http12.message.codec.PlainTextCodecFactory
+xml=org.apache.dubbo.remoting.http12.message.codec.XmlCodecFactory
+urlencoded=org.apache.dubbo.remoting.http12.message.codec.UrlEncodeFormCodecFactory
\ No newline at end of file
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodeUtilsTest.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodeUtilsTest.java
new file mode 100644
index 0000000000..b8436c1c17
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodeUtilsTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import org.apache.dubbo.remoting.http12.HttpHeaderNames;
+import org.apache.dubbo.remoting.http12.HttpHeaders;
+import 
org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
+import org.apache.dubbo.remoting.http12.message.MediaType;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+
+import java.util.Collections;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class CodeUtilsTest {
+
+    @Test
+    void testDetermineHttpCodec() {
+        CodecUtils codecUtils = new CodecUtils(FrameworkModel.defaultModel());
+        HttpHeaders headers = new HttpHeaders();
+        headers.put(
+                HttpHeaderNames.CONTENT_TYPE.getName(),
+                
Collections.singletonList(MediaType.APPLICATION_JSON_VALUE.getName()));
+        HttpMessageDecoder decoder =
+                
codecUtils.determineHttpMessageDecoder(FrameworkModel.defaultModel(), 
headers.getContentType(), null);
+        Assertions.assertNotNull(decoder);
+        Assertions.assertEquals(JsonPbCodec.class, decoder.getClass());
+
+        HttpMessageEncoder encoder;
+        // If no Accept header provided, use Content-Type to find encoder
+        encoder = 
codecUtils.determineHttpMessageEncoder(FrameworkModel.defaultModel(), headers, 
null);
+        Assertions.assertNotNull(encoder);
+        Assertions.assertEquals(JsonPbCodec.class, encoder.getClass());
+
+        HttpHeaders headers1 = new HttpHeaders();
+        headers1.put(
+                HttpHeaderNames.CONTENT_TYPE.getName(),
+                
Collections.singletonList(MediaType.MULTIPART_FORM_DATA.getName()));
+        decoder =
+                
codecUtils.determineHttpMessageDecoder(FrameworkModel.defaultModel(), 
headers1.getContentType(), null);
+        Assertions.assertNotNull(decoder);
+        Assertions.assertEquals(MultipartDecoder.class, decoder.getClass());
+        Assertions.assertThrows(
+                UnsupportedMediaTypeException.class,
+                () -> 
codecUtils.determineHttpMessageEncoder(FrameworkModel.defaultModel(), headers1, 
null));
+
+        headers1.put(
+                HttpHeaderNames.ACCEPT.getName(),
+                
Collections.singletonList(MediaType.APPLICATION_JSON_VALUE.getName()));
+        encoder = 
codecUtils.determineHttpMessageEncoder(FrameworkModel.defaultModel(), headers1, 
null);
+        Assertions.assertNotNull(encoder);
+        Assertions.assertEquals(JsonPbCodec.class, encoder.getClass());
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodecTest.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodecTest.java
new file mode 100644
index 0000000000..f36f6cc76f
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/CodecTest.java
@@ -0,0 +1,399 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import org.apache.dubbo.remoting.http12.exception.DecodeException;
+import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Random;
+
+import com.google.common.base.Charsets;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public class CodecTest {
+
+    final String MULTIPART_SAMPLE_1 = "--example-part-boundary\r\n"
+            + "Content-Disposition: form-data; name=\"username\"\r\n"
+            + "Content-Type: text/plain\r\n"
+            + "\r\n"
+            + "LuYue\r\n"
+            + "--example-part-boundary\r\n"
+            + "Content-Disposition: form-data; name=\"userdetail\"\r\n"
+            + "Content-Type: application/json\r\n"
+            + "\r\n"
+            + "{\"location\":\"beijing\",\"username\":\"LuYue\"}\r\n"
+            + "--example-part-boundary\r\n"
+            + "Content-Disposition: form-data; name=\"userimg\"; 
filename=\"user.jpeg\"\r\n"
+            + "Content-Type: image/jpeg\r\n"
+            + "\r\n"
+            + "<binary-image data>\r\n"
+            + "--example-part-boundary--\r\n";
+
+    final String MULTIPART_SAMPLE_2 = "--boundary123\r\n" + 
"Content-Disposition: form-data; name=\"text\"\r\n"
+            + "Content-Type: text/plain\r\n"
+            + "\r\n"
+            + "simple text\r\n"
+            + "--boundary123\r\n"
+            + "Content-Disposition: form-data; name=\"file\"; 
filename=\"example.txt\"\r\n"
+            + "Content-Type: text/plain\r\n"
+            + "\r\n"
+            + "This is the content of the file.\r\n"
+            + "--boundary123--\r\n";
+
+    final String MULTIPART_SAMPLE_3 = "--boundaryABC\r\n" + 
"Content-Disposition: form-data; name=\"someContent\"\r\n"
+            + "\r\n"
+            + "这是一些中文内容\r\n"
+            + "--boundaryABC\r\n"
+            + "Content-Disposition: form-data; name=\"emoji\"\r\n"
+            + "\r\n"
+            + "\uD83D\uDE0A\r\n"
+            + "--boundaryABC--";
+
+    final String MULTIPART_SAMPLE_4 = "--longValue\r\n" + 
"Content-Disposition: form-data; name=\"long\"\r\n"
+            + "\r\n"
+            + "This is a really long value that continues for many lines.This 
is a really long value that continues for many lines.This is a really long 
value that continues for many lines.This is a really long value that continues 
for many lines.This is a really long value that continues for many lines.This 
is a really long value that continues for many lines.This is a really long 
value that continues for many lines.This is a really long value that continues 
for many lines.This is a rea [...]
+            + "--longValue--\r\n";
+
+    final String MULTIPART_SAMPLE_5 = "--specialChar\r\n" + 
"Content-Disposition: form-data; name=\"special\"\r\n"
+            + "\r\n"
+            + "Line 1\n"
+            + "Line 2\r\n"
+            + "--Line 3--\n"
+            + "Line 4\n\r\n"
+            + "--specialChar--";
+
+    CodecUtils codecUtils;
+
+    @BeforeEach
+    void beforeAll() {
+        codecUtils = 
FrameworkModel.defaultModel().getBeanFactory().getOrRegisterBean(CodecUtils.class);
+    }
+
+    @Test
+    void testMultipartForm1() {
+        InputStream in = new 
ByteArrayInputStream(MULTIPART_SAMPLE_1.getBytes());
+        HttpMessageDecoder decoder = new MultipartDecoder(
+                null, FrameworkModel.defaultModel(), "multipart/form-data; 
boundary=example-part-boundary", codecUtils);
+        Object[] result = decoder.decode(in, new Class[] {String.class, 
User.class, byte[].class});
+        Assertions.assertEquals("LuYue", result[0]);
+        Assertions.assertTrue(result[1] instanceof User);
+        Assertions.assertEquals("LuYue", ((User) result[1]).getUsername());
+        Assertions.assertEquals("beijing", ((User) result[1]).getLocation());
+        Assertions.assertEquals("<binary-image data>", new String((byte[]) 
result[2], Charsets.UTF_8));
+    }
+
+    @Test
+    void testMultipartForm2() {
+        InputStream in = new 
ByteArrayInputStream(MULTIPART_SAMPLE_2.getBytes());
+        HttpMessageDecoder decoder = new MultipartDecoder(
+                null, FrameworkModel.defaultModel(), "multipart/form-data; 
boundary=boundary123", codecUtils);
+        Object[] result = decoder.decode(in, new Class[] {String.class, 
byte[].class});
+        Assertions.assertEquals("simple text", result[0]);
+        Assertions.assertEquals(
+                "This is the content of the file.", new String((byte[]) 
result[1], StandardCharsets.US_ASCII));
+    }
+
+    @Test
+    void testMultipartForm3() {
+        InputStream in = new 
ByteArrayInputStream(MULTIPART_SAMPLE_3.getBytes());
+        HttpMessageDecoder decoder = new MultipartDecoder(
+                null, FrameworkModel.defaultModel(), "multipart/form-data; 
boundary=boundaryABC", codecUtils);
+        Object[] result = decoder.decode(in, new Class[] {String.class, 
String.class});
+        Assertions.assertEquals("这是一些中文内容", result[0]);
+        Assertions.assertEquals("😊", result[1]);
+    }
+
+    @Test
+    void testMultipartForm4() {
+        InputStream in = new 
ByteArrayInputStream(MULTIPART_SAMPLE_4.getBytes());
+        HttpMessageDecoder decoder = new MultipartDecoder(
+                null, FrameworkModel.defaultModel(), "multipart/form-data; 
boundary=longValue", codecUtils);
+        Object[] result = decoder.decode(in, new Class[] {String.class});
+        Assertions.assertEquals(
+                "This is a really long value that continues for many 
lines.This is a really long value that continues for many lines.This is a 
really long value that continues for many lines.This is a really long value 
that continues for many lines.This is a really long value that continues for 
many lines.This is a really long value that continues for many lines.This is a 
really long value that continues for many lines.This is a really long value 
that continues for many lines.This is a r [...]
+                result[0]);
+    }
+
+    @Test
+    void testMultipartForm5() {
+        InputStream in = new 
ByteArrayInputStream(MULTIPART_SAMPLE_5.getBytes());
+        HttpMessageDecoder decoder = new MultipartDecoder(
+                null, FrameworkModel.defaultModel(), "multipart/form-data; 
boundary=specialChar", codecUtils);
+        Object[] result = decoder.decode(in, new Class[] {String.class});
+        Assertions.assertEquals("Line 1\n" + "Line 2\r\n" + "--Line 3--\n" + 
"Line 4\n", result[0]);
+    }
+
+    @Test
+    void testMultipartFormBodyBoundary() {
+        // check if codec can handle boundary correctly when the end delimiter 
just beyond the buffer.
+        // header buffer size: 128; body buffer size: 256
+        // --example-boundary\r\n   [20bytes]
+        // Content-Type: plain/text [paddings]\r\n\r\n [108bytes]
+        // body1r\n [238bytes, binary data]
+        // --example-boundary--\r\n [22bytes] , last --\r\n [4bytes] beyond 
buffer
+        byte[] boundary = "--example-boundary\r\n".getBytes();
+        byte[] header = "Content-Type: plain/text".getBytes();
+        byte[] headerPadding = new byte[128 - header.length - boundary.length 
- "\r\n\r\n".length()];
+        byte[] headerBytes = new byte[128];
+        byte[] body1 = new byte[238];
+        byte[] end = "--example-boundary--\r\n".getBytes();
+        byte[] bodyWithEnd = new byte[260];
+
+        Random random = new Random();
+        random.nextBytes(body1);
+        body1[236] = '\r';
+        body1[237] = '\n';
+        Arrays.fill(headerPadding, (byte) 0);
+
+        System.arraycopy(boundary, 0, headerBytes, 0, boundary.length);
+        System.arraycopy(header, 0, headerBytes, boundary.length, 
header.length);
+
+        System.arraycopy(headerPadding, 0, headerBytes, boundary.length + 
header.length, headerPadding.length);
+        System.arraycopy(
+                "\r\n\r\n".getBytes(),
+                0,
+                headerBytes,
+                boundary.length + header.length + headerPadding.length,
+                "\r\n\r\n".length());
+        System.arraycopy(body1, 0, bodyWithEnd, 0, body1.length);
+        System.arraycopy(end, 0, bodyWithEnd, body1.length, end.length);
+
+        byte[] fullRequestBody = new byte[256 + 128 + 4];
+        System.arraycopy(headerBytes, 0, fullRequestBody, 0, 
headerBytes.length);
+        System.arraycopy(bodyWithEnd, 0, fullRequestBody, headerBytes.length, 
bodyWithEnd.length);
+
+        HttpMessageDecoder decoder = new MultipartDecoderFactory()
+                .createCodec(null, FrameworkModel.defaultModel(), 
"multipart/form-data; boundary=example-boundary");
+        byte[] res = (byte[]) decoder.decode(new 
ByteArrayInputStream(fullRequestBody), byte[].class);
+
+        for (int k = 0; k < body1.length - 2; k++) {
+            Assertions.assertEquals(body1[k], res[k]);
+        }
+    }
+
+    @Test
+    void testMultipartFormBodyBoundary2() {
+        // check if codec can handle boundary correctly when the end delimiter 
just beyond the buffer.
+        // header buffer size: 128; body buffer size: 256
+        // --example-boundary-\r\n   [21bytes]
+        // Content-Type: plain/text [paddings]\r\n\r\n [107bytes]
+        // body1r\n  [237bytes, binary data]
+        // --example-boundary-\r\n [21bytes] , \r\n [2bytes] beyond buffer
+        // body2\r\n [7bytes, text data]
+        // --example-boundary--- [23bytes]
+        byte[] boundary = "--example-boundary-\r\n".getBytes();
+        byte[] subHeader = "Content-Type: plain/text".getBytes();
+        byte[] subHeaderWithCRLF = "Content-Type: 
plain/text\r\n\r\n".getBytes();
+        byte[] headerPadding = new byte[128 - subHeader.length - 
boundary.length - "\r\n\r\n".length()];
+        byte[] headerBytes = new byte[128];
+        byte[] body1 = new byte[237];
+        byte[] body1WithEnd = new byte[body1.length + boundary.length];
+        byte[] body2 = "body2\r\n".getBytes();
+        byte[] end = "--example-boundary---\r\n".getBytes();
+
+        Random random = new Random();
+        random.nextBytes(body1);
+        body1[body1.length - 1] = '\n';
+        body1[body1.length - 2] = '\r';
+        Arrays.fill(headerPadding, (byte) 0);
+
+        System.arraycopy(boundary, 0, headerBytes, 0, boundary.length);
+        System.arraycopy(subHeader, 0, headerBytes, boundary.length, 
subHeader.length);
+        System.arraycopy(headerPadding, 0, headerBytes, boundary.length + 
subHeader.length, headerPadding.length);
+        System.arraycopy(
+                "\r\n\r\n".getBytes(),
+                0,
+                headerBytes,
+                boundary.length + subHeader.length + headerPadding.length,
+                "\r\n\r\n".length());
+        System.arraycopy(body1, 0, body1WithEnd, 0, body1.length);
+        System.arraycopy(boundary, 0, body1WithEnd, body1.length, 
boundary.length);
+
+        byte[] fullRequestBody = new byte
+                [headerBytes.length + body1WithEnd.length + 
subHeaderWithCRLF.length + body2.length + end.length];
+        System.arraycopy(headerBytes, 0, fullRequestBody, 0, 
headerBytes.length);
+        System.arraycopy(body1WithEnd, 0, fullRequestBody, headerBytes.length, 
body1WithEnd.length);
+        System.arraycopy(
+                subHeaderWithCRLF,
+                0,
+                fullRequestBody,
+                headerBytes.length + body1WithEnd.length,
+                subHeaderWithCRLF.length);
+        System.arraycopy(
+                body2,
+                0,
+                fullRequestBody,
+                headerBytes.length + body1WithEnd.length + 
subHeaderWithCRLF.length,
+                body2.length);
+        System.arraycopy(
+                end,
+                0,
+                fullRequestBody,
+                headerBytes.length + body1WithEnd.length + 
subHeaderWithCRLF.length + body2.length,
+                end.length);
+
+        HttpMessageDecoder decoder = new MultipartDecoder(
+                null, FrameworkModel.defaultModel(), "multipart/form-data; 
boundary=example-boundary-", codecUtils);
+        Object[] r =
+                decoder.decode(new ByteArrayInputStream(fullRequestBody), new 
Class[] {byte[].class, String.class});
+        byte[] res = (byte[]) r[0];
+        for (int k = 0; k < body1.length - 2; k++) {
+            Assertions.assertEquals(body1[k], res[k]);
+        }
+        String res2 = (String) r[1];
+        Assertions.assertEquals("body2", res2);
+    }
+
+    @Test
+    void testUrlForm() {
+        String content = "Hello=World&Apache=Dubbo&id=10086";
+        InputStream in = new ByteArrayInputStream(content.getBytes());
+        UrlEncodeFormCodecFactory factory = new 
UrlEncodeFormCodecFactory(FrameworkModel.defaultModel());
+        HttpMessageCodec codec = factory.createCodec(null, 
FrameworkModel.defaultModel(), null);
+        Object res = codec.decode(in, Map.class);
+        Assertions.assertTrue(res instanceof Map);
+        Map<String, String> r = (Map<String, String>) res;
+        Assertions.assertEquals("World", r.get("Hello"));
+        Assertions.assertEquals("Dubbo", r.get("Apache"));
+        Assertions.assertEquals("10086", r.get("id"));
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        codec.encode(outputStream, r);
+        Assertions.assertEquals(content, outputStream.toString());
+        try {
+            in.reset();
+        } catch (IOException e) {
+        }
+        Object[] res2 = codec.decode(in, new Class[] {String.class, 
String.class, Long.class});
+        Assertions.assertEquals("World", res2[0]);
+        Assertions.assertEquals("Dubbo", res2[1]);
+        Assertions.assertEquals(10086L, res2[2]);
+        outputStream = new ByteArrayOutputStream();
+        codec.encode(outputStream, content);
+        Assertions.assertEquals(content, outputStream.toString());
+    }
+
+    @Test
+    void testUrlForm2() {
+        InputStream in = new 
ByteArrayInputStream("Hello=World&Apache=Dubbo&empty1=&empty2=".getBytes());
+        HttpMessageCodec codec = new 
UrlEncodeFormCodecFactory(FrameworkModel.defaultModel())
+                .createCodec(null, FrameworkModel.defaultModel(), null);
+        Object res = codec.decode(in, Map.class);
+        Assertions.assertTrue(res instanceof Map);
+        Map<String, String> r = (Map<String, String>) res;
+        Assertions.assertEquals("World", r.get("Hello"));
+        Assertions.assertEquals("Dubbo", r.get("Apache"));
+        Assertions.assertEquals("", r.get("empty1"));
+        Assertions.assertEquals("", r.get("empty2"));
+    }
+
+    @Test
+    void testUrlForm3() {
+        InputStream in = new 
ByteArrayInputStream("empty1=&empty2=&Hello=world&empty3=&Apache=dubbo&".getBytes());
+        HttpMessageCodec codec = new 
UrlEncodeFormCodecFactory(FrameworkModel.defaultModel())
+                .createCodec(null, FrameworkModel.defaultModel(), null);
+        Object res = codec.decode(in, Map.class);
+        Assertions.assertTrue(res instanceof Map);
+        Map<String, String> r = (Map<String, String>) res;
+        Assertions.assertEquals("world", r.get("Hello"));
+        Assertions.assertEquals("dubbo", r.get("Apache"));
+        Assertions.assertEquals("", r.get("empty1"));
+        Assertions.assertEquals("", r.get("empty2"));
+        Assertions.assertEquals("", r.get("empty3"));
+    }
+
+    @Test
+    void testUrlForm4() {
+        InputStream in = new 
ByteArrayInputStream("empty1=&empty2=&Hello=world&你好=世界&empty3=&Apache=dubbo&".getBytes());
+        HttpMessageCodec codec = new 
UrlEncodeFormCodecFactory(FrameworkModel.defaultModel())
+                .createCodec(null, FrameworkModel.defaultModel(), null);
+        Object res = codec.decode(in, Map.class);
+        Assertions.assertTrue(res instanceof Map);
+        Map<String, String> r = (Map<String, String>) res;
+        Assertions.assertEquals("world", r.get("Hello"));
+        Assertions.assertEquals("dubbo", r.get("Apache"));
+        Assertions.assertEquals("", r.get("empty1"));
+        Assertions.assertEquals("", r.get("empty2"));
+        Assertions.assertEquals("", r.get("empty3"));
+        Assertions.assertEquals("世界", r.get("你好"));
+    }
+
+    @Test
+    void testXml() {
+        String content = "<?xml version=\"1.0\" encoding=\"UTF-8\" 
standalone=\"yes\"?>"
+                + "<user><location>New 
York</location><username>JohnDoe</username></user>";
+        InputStream in = new ByteArrayInputStream(content.getBytes());
+        HttpMessageCodec codec = new XmlCodecFactory().createCodec(null, 
FrameworkModel.defaultModel(), null);
+        User user = (User) codec.decode(in, User.class);
+        Assertions.assertEquals("JohnDoe", user.getUsername());
+        Assertions.assertEquals("New York", user.getLocation());
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        codec.encode(outputStream, user);
+        String res = outputStream.toString();
+        Assertions.assertEquals(content, res);
+    }
+
+    @Test
+    void testPlainText() {
+        byte[] asciiBytes = new byte[] {
+            0x48, 0x65, 0x6C, 0x6C,
+            0x6F, 0x2C, 0x20, 0x77,
+            0x6F, 0x72, 0x6C, 0x64
+        };
+        byte[] utf8Bytes = new byte[] {
+            (byte) 0xE4, (byte) 0xBD, (byte) 0xA0,
+            (byte) 0xE5, (byte) 0xA5, (byte) 0xBD,
+            (byte) 0xEF, (byte) 0xBC, (byte) 0x8C,
+            (byte) 0xE4, (byte) 0xB8, (byte) 0x96,
+            (byte) 0xE7, (byte) 0x95, (byte) 0x8C
+        };
+        byte[] utf16Bytes = new byte[] {0x4F, 0x60, 0x59, 0x7D, (byte) 0xFF, 
0x0C, 0x4E, 0x16, 0x75, 0x4C};
+        InputStream in = new ByteArrayInputStream(asciiBytes);
+        HttpMessageCodec codec = new PlainTextCodecFactory()
+                .createCodec(null, FrameworkModel.defaultModel(), "text/plain; 
charset=ASCII");
+        String res = (String) codec.decode(in, String.class);
+        Assertions.assertEquals("Hello, world", res);
+
+        in = new ByteArrayInputStream(utf8Bytes);
+        codec = new PlainTextCodec("text/plain; charset=UTF-8");
+        res = (String) codec.decode(in, String.class);
+        Assertions.assertEquals("你好,世界", res);
+
+        in = new ByteArrayInputStream(utf16Bytes);
+        codec = new PlainTextCodec("text/plain; charset=UTF-16");
+        res = (String) codec.decode(in, String.class);
+        Assertions.assertEquals("你好,世界", res);
+    }
+
+    @Test
+    void testUnsupportedCharset() {
+        HttpMessageCodec codec = new PlainTextCodec("text/plain; 
charset=unsupported");
+        Assertions.assertThrows(
+                DecodeException.class, () -> codec.decode(new 
ByteArrayInputStream(new byte[] {}), String.class));
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/User.java
similarity index 51%
copy from 
dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java
copy to 
dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/User.java
index dc57c7bf84..314c4a1b61 100644
--- 
a/dubbo-remoting/dubbo-remoting-http12/src/main/java/org/apache/dubbo/remoting/http12/message/DefaultListeningDecoder.java
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/User.java
@@ -14,36 +14,44 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.dubbo.remoting.http12.message;
+package org.apache.dubbo.remoting.http12.message.codec;
 
-import java.io.InputStream;
+import javax.xml.bind.annotation.XmlRootElement;
 
-public class DefaultListeningDecoder implements ListeningDecoder {
+import java.io.Serializable;
 
-    private final HttpMessageCodec httpMessageCodec;
+@XmlRootElement
+public class User implements Serializable {
 
-    private final Class<?>[] targetTypes;
+    private String username;
 
-    private Listener listener;
+    private String location;
 
-    public DefaultListeningDecoder(HttpMessageCodec httpMessageCodec, 
Class<?>[] targetTypes) {
-        this.httpMessageCodec = httpMessageCodec;
-        this.targetTypes = targetTypes;
+    public User() {}
+
+    public User(String username, String location) {
+        this.username = username;
+        this.location = location;
     }
 
-    @Override
-    public void setListener(Listener listener) {
-        this.listener = listener;
+    public String getUsername() {
+        return username;
     }
 
-    @Override
-    public void decode(InputStream inputStream) {
-        Object[] decode = this.httpMessageCodec.decode(inputStream, 
targetTypes);
-        this.listener.onMessage(decode);
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
     }
 
     @Override
-    public void close() {
-        this.listener.onClose();
+    public String toString() {
+        return "User{" + "username='" + username + '\'' + ", location='" + 
location + '\'' + '}';
     }
 }
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/XmlSafetyTest.java
 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/XmlSafetyTest.java
new file mode 100644
index 0000000000..bc5188ab5f
--- /dev/null
+++ 
b/dubbo-remoting/dubbo-remoting-http12/src/test/java/org/apache/dubbo/remoting/http12/message/codec/XmlSafetyTest.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ *     http://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 org.apache.dubbo.remoting.http12.message.codec;
+
+import java.io.*;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+@EnabledOnOs(OS.LINUX)
+public class XmlSafetyTest {
+
+    ProcessChecker checker = new ProcessChecker();
+
+    @BeforeEach
+    void setUp() throws Exception {
+        checker.prepare();
+    }
+
+    @AfterEach
+    void check() throws Exception {
+        checker.check();
+    }
+
+    @Test
+    void testSafe1() {
+        try {
+            InputStream in = new ByteArrayInputStream(("<xml>\n" + "  
<dynamic-proxy>\n"
+                            + "    <interface>java.util.List</interface>\n"
+                            + "    <handler 
class=\"java.beans.EventHandler\">\n"
+                            + "      <target 
class=\"java.lang.ProcessBuilder\">\n"
+                            + "        <command>\n"
+                            + "          <string>" + "sleep" + "</string>\n"
+                            + "          <string>" + "60" + "</string>\n"
+                            + "        </command>\n"
+                            + "      </target>\n"
+                            + "      <action>start</action>\n"
+                            + "    </handler>\n"
+                            + "  </dynamic-proxy>\n"
+                            + "</xml>")
+                    .getBytes());
+            new XmlCodec().decode(in, Object.class);
+        } catch (Exception e) {
+        }
+    }
+
+    @Test
+    void testSafe2() {
+        try {
+            InputStream in = new ByteArrayInputStream(("<java>\n" + "  <object 
class=\"java.lang.Runtime\">\n"
+                            + "    <void method=\"exec\">\n"
+                            + "      <string>" + "sleep" + "</string>\n"
+                            + "      <string>" + "60" + "</string>\n"
+                            + "    </void>\n"
+                            + "  </object>\n"
+                            + "</java>")
+                    .getBytes());
+            new XmlCodec().decode(in, Object.class);
+        } catch (Exception e) {
+        }
+    }
+
+    static class ProcessChecker {
+        Set<String> processesBefore;
+
+        public Set<String> getProcesses() {
+            try {
+                Set<String> processes = new HashSet<>();
+                Process process = Runtime.getRuntime().exec("ps -e");
+                try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(process.getInputStream()))) {
+                    String line;
+                    while ((line = reader.readLine()) != null) {
+                        processes.add(line);
+                    }
+                }
+                return processes;
+            } catch (Exception e) {
+            }
+            return Collections.emptySet();
+        }
+
+        public void prepare() {
+            processesBefore = getProcesses();
+        }
+
+        public void check() throws Exception {
+            Set<String> processesAfter = getProcesses();
+            for (String msg : processesAfter) {
+                if (msg.contains("sleep")) {
+                    throw new Exception("Command executed when XML 
deserialization.");
+                }
+            }
+        }
+    }
+}
diff --git 
a/dubbo-remoting/dubbo-remoting-http12/src/test/resources/log4j2-test.xml 
b/dubbo-remoting/dubbo-remoting-http12/src/test/resources/log4j2-test.xml
new file mode 100644
index 0000000000..ba99f52cc2
--- /dev/null
+++ b/dubbo-remoting/dubbo-remoting-http12/src/test/resources/log4j2-test.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You 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
+  ~
+  ~     http://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.
+  -->
+<Configuration status="WARN">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT" follow="true">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} |-%highlight{%-5p} [%t] 
%40.40c:%-3L -| 
%m%n%rEx{filters(jdk.internal.reflect,java.lang.reflect,sun.reflect,org.junit,org.mockito)}"
 charset="UTF-8"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="info">
+            <AppenderRef ref="Console"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
index 89f09e93a5..1b8d509088 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/AbstractServerTransportListener.java
@@ -26,6 +26,7 @@ import org.apache.dubbo.remoting.http12.HttpChannel;
 import org.apache.dubbo.remoting.http12.HttpHeaderNames;
 import org.apache.dubbo.remoting.http12.HttpHeaders;
 import org.apache.dubbo.remoting.http12.HttpInputMessage;
+import org.apache.dubbo.remoting.http12.HttpMetadata;
 import org.apache.dubbo.remoting.http12.HttpStatus;
 import org.apache.dubbo.remoting.http12.HttpTransportListener;
 import org.apache.dubbo.remoting.http12.RequestMetadata;
@@ -33,9 +34,9 @@ import 
org.apache.dubbo.remoting.http12.exception.HttpStatusException;
 import org.apache.dubbo.remoting.http12.exception.IllegalPathException;
 import org.apache.dubbo.remoting.http12.exception.UnimplementedException;
 import 
org.apache.dubbo.remoting.http12.exception.UnsupportedMediaTypeException;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
 import org.apache.dubbo.remoting.http12.message.MethodMetadata;
+import org.apache.dubbo.remoting.http12.message.codec.CodecUtils;
 import org.apache.dubbo.rpc.HeaderFilter;
 import org.apache.dubbo.rpc.Invoker;
 import org.apache.dubbo.rpc.PathResolver;
@@ -83,7 +84,7 @@ public abstract class AbstractServerTransportListener<HEADER 
extends RequestMeta
 
     private final List<HeaderFilter> headerFilters;
 
-    private HttpMessageCodec httpMessageCodec;
+    private HttpMessageDecoder httpMessageDecoder;
 
     private Invoker<?> invoker;
 
@@ -103,6 +104,8 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
 
     private HttpMessageListener httpMessageListener;
 
+    protected CodecUtils codecUtils;
+
     public AbstractServerTransportListener(FrameworkModel frameworkModel, URL 
url, HttpChannel httpChannel) {
         this.frameworkModel = frameworkModel;
         this.url = url;
@@ -111,6 +114,7 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
                 
frameworkModel.getExtensionLoader(PathResolver.class).getDefaultExtension();
         this.headerFilters =
                 
frameworkModel.getExtensionLoader(HeaderFilter.class).getActivateExtension(url, 
HEADER_FILTER_KEY);
+        this.codecUtils = 
frameworkModel.getBeanFactory().getOrRegisterBean(CodecUtils.class);
     }
 
     protected Executor initializeExecutor(HEADER metadata) {
@@ -120,6 +124,7 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
 
     @Override
     public void onMetadata(HEADER metadata) {
+
         try {
             this.executor = initializeExecutor(metadata);
         } catch (Throwable throwable) {
@@ -165,11 +170,8 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
         if (invoker == null) {
             throw new UnimplementedException(serviceName);
         }
-        HttpMessageCodec httpMessageCodec = 
determineHttpMessageCodec(contentType);
-        if (httpMessageCodec == null) {
-            throw new UnsupportedMediaTypeException(contentType);
-        }
-        this.httpMessageCodec = httpMessageCodec;
+        this.httpMessageDecoder =
+                codecUtils.determineHttpMessageDecoder(getFrameworkModel(), 
headers.getContentType(), getUrl());
         setServiceDescriptor(findServiceDescriptor(invoker, serviceName, 
hasStub));
         setHttpMessageListener(newHttpMessageListener());
         onMetadataCompletion(metadata);
@@ -248,16 +250,6 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
         return invoker;
     }
 
-    protected HttpMessageCodec determineHttpMessageCodec(String contentType) {
-        for (HttpMessageCodecFactory httpMessageCodecFactory :
-                
frameworkModel.getExtensionLoader(HttpMessageCodecFactory.class).getActivateExtensions())
 {
-            if (httpMessageCodecFactory.support(contentType)) {
-                return httpMessageCodecFactory.createCodec(invoker.getUrl(), 
frameworkModel);
-            }
-        }
-        return null;
-    }
-
     private static ServiceDescriptor findServiceDescriptor(Invoker<?> invoker, 
String serviceName, boolean hasStub)
             throws UnimplementedException {
         ServiceDescriptor result;
@@ -421,8 +413,12 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
         return methodMetadata;
     }
 
-    protected HttpMessageCodec getHttpMessageCodec() {
-        return httpMessageCodec;
+    protected HttpMessageDecoder getHttpMessageDecoder() {
+        return this.httpMessageDecoder;
+    }
+
+    protected CodecUtils getCodecUtils() {
+        return this.codecUtils;
     }
 
     protected void setHttpMessageListener(HttpMessageListener 
httpMessageListener) {
@@ -441,6 +437,10 @@ public abstract class 
AbstractServerTransportListener<HEADER extends RequestMeta
         return url;
     }
 
+    protected HttpMetadata getMetadata() {
+        return httpMetadata;
+    }
+
     public boolean isHasStub() {
         return hasStub;
     }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompressibleCodec.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompressibleEncoder.java
similarity index 63%
rename from 
dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompressibleCodec.java
rename to 
dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompressibleEncoder.java
index 7da92bd17f..60c9caf529 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompressibleCodec.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/CompressibleEncoder.java
@@ -16,22 +16,20 @@
  */
 package org.apache.dubbo.rpc.protocol.tri.h12;
 
-import org.apache.dubbo.remoting.http12.exception.DecodeException;
 import org.apache.dubbo.remoting.http12.exception.EncodeException;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoder;
 import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.rpc.protocol.tri.compressor.Compressor;
 
-import java.io.InputStream;
 import java.io.OutputStream;
 
-public class CompressibleCodec implements HttpMessageCodec {
+public class CompressibleEncoder implements HttpMessageEncoder {
 
-    private final HttpMessageCodec delegate;
+    private final HttpMessageEncoder delegate;
 
     private Compressor compressor = Compressor.NONE;
 
-    public CompressibleCodec(HttpMessageCodec delegate) {
+    public CompressibleEncoder(HttpMessageEncoder delegate) {
         this.delegate = delegate;
     }
 
@@ -39,33 +37,16 @@ public class CompressibleCodec implements HttpMessageCodec {
         this.compressor = compressor;
     }
 
-    @Override
     public void encode(OutputStream outputStream, Object data) throws 
EncodeException {
         delegate.encode(compressor.decorate(outputStream), data);
     }
 
-    @Override
-    public Object decode(InputStream inputStream, Class<?> targetType) throws 
DecodeException {
-        return delegate.decode(inputStream, targetType);
-    }
-
-    @Override
     public void encode(OutputStream outputStream, Object[] data) throws 
EncodeException {
         delegate.encode(outputStream, data);
     }
 
     @Override
-    public Object[] decode(InputStream inputStream, Class<?>[] targetTypes) 
throws DecodeException {
-        return delegate.decode(inputStream, targetTypes);
-    }
-
-    @Override
-    public boolean support(String contentType) {
-        return delegate.support(contentType);
-    }
-
-    @Override
-    public MediaType contentType() {
-        return delegate.contentType();
+    public MediaType mediaType() {
+        return delegate.mediaType();
     }
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java
index 2c5041d6c8..96b18cf2ec 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodec.java
@@ -16,7 +16,6 @@
  */
 package org.apache.dubbo.rpc.protocol.tri.h12.grpc;
 
-import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.remoting.http12.exception.DecodeException;
 import org.apache.dubbo.remoting.http12.exception.EncodeException;
 import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
@@ -30,13 +29,6 @@ import com.google.protobuf.Message;
 
 import static 
org.apache.dubbo.common.constants.CommonConstants.PROTOBUF_MESSAGE_CLASS_NAME;
 
-/**
- * compatible low version.
- * version < 3.3
- *
- * @since 3.3
- */
-@Activate
 public class GrpcCompositeCodec implements HttpMessageCodec {
 
     private static final MediaType MEDIA_TYPE = new MediaType("application", 
"grpc");
@@ -106,15 +98,10 @@ public class GrpcCompositeCodec implements 
HttpMessageCodec {
     }
 
     @Override
-    public MediaType contentType() {
+    public MediaType mediaType() {
         return MEDIA_TYPE;
     }
 
-    @Override
-    public boolean support(String contentType) {
-        return contentType.startsWith(MEDIA_TYPE.getName());
-    }
-
     private static boolean isProtobuf(Object data) {
         if (data == null) {
             return false;
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
index 792fde774d..29a7de9dfd 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcCompositeCodecFactory.java
@@ -19,18 +19,19 @@ package org.apache.dubbo.rpc.protocol.tri.h12.grpc;
 import org.apache.dubbo.common.URL;
 import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory;
+import org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory;
 import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.remoting.utils.UrlUtils;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
 @Activate
-public class GrpcCompositeCodecFactory implements HttpMessageCodecFactory {
+public class GrpcCompositeCodecFactory implements HttpMessageEncoderFactory, 
HttpMessageDecoderFactory {
 
     private static final MediaType MEDIA_TYPE = new MediaType("application", 
"grpc");
 
     @Override
-    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel) {
+    public HttpMessageCodec createCodec(URL url, FrameworkModel 
frameworkModel, String mediaType) {
         final String serializeName = UrlUtils.serializationOrDefault(url);
         WrapperHttpMessageCodec wrapperHttpMessageCodec = new 
WrapperHttpMessageCodec(url, frameworkModel);
         wrapperHttpMessageCodec.setSerializeType(serializeName);
@@ -39,12 +40,7 @@ public class GrpcCompositeCodecFactory implements 
HttpMessageCodecFactory {
     }
 
     @Override
-    public MediaType contentType() {
+    public MediaType mediaType() {
         return MEDIA_TYPE;
     }
-
-    @Override
-    public boolean support(String contentType) {
-        return contentType.startsWith(MEDIA_TYPE.getName());
-    }
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java
index 174a1756f4..e781bc0c71 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHeaderNames.java
@@ -19,7 +19,8 @@ package org.apache.dubbo.rpc.protocol.tri.h12.grpc;
 public enum GrpcHeaderNames {
     GRPC_STATUS("grpc-status"),
     GRPC_MESSAGE("grpc-message"),
-    GRPC_ENCODING("grpc-encoding"),
+    GRPC_ENCODING("grpc-encoding"), // client request compress type
+    GRPC_ACCEPT_ENCODING("grpc-accept-encoding"), // client required response 
compress type
     GRPC_TIMEOUT("grpc-timeout"),
     ;
 
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java
index d8f7655e54..de216cee56 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/GrpcHttp2ServerTransportListener.java
@@ -210,10 +210,13 @@ public class GrpcHttp2ServerTransportListener extends 
GenericHttp2ServerTranspor
                     // replace decoder
                     HttpMessageListener httpMessageListener =
                             
GrpcHttp2ServerTransportListener.super.newHttpMessageListener();
-                    GrpcCompositeCodec grpcCompositeCodec = 
(GrpcCompositeCodec) getHttpMessageCodec();
+                    GrpcCompositeCodec grpcCompositeCodec = 
(GrpcCompositeCodec) getHttpMessageDecoder();
+                    
grpcCompositeCodec.setDecodeTypes(getMethodMetadata().getActualRequestTypes());
                     grpcCompositeCodec.setEncodeTypes(
                             new Class[] 
{getMethodMetadata().getActualResponseType()});
-                    
grpcCompositeCodec.setDecodeTypes(getMethodMetadata().getActualRequestTypes());
+                    GrpcHttp2ServerTransportListener.super
+                            .getServerChannelObserver()
+                            .setResponseEncoder(grpcCompositeCodec);
                     setHttpMessageListener(httpMessageListener);
                 }
                 transferToOutputStream(merge, new ByteArrayInputStream(data));
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java
index 1d6fce91df..011fd6b8a9 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/ProtobufHttpMessageCodec.java
@@ -16,7 +16,6 @@
  */
 package org.apache.dubbo.rpc.protocol.tri.h12.grpc;
 
-import org.apache.dubbo.common.extension.Activate;
 import org.apache.dubbo.remoting.http12.exception.DecodeException;
 import org.apache.dubbo.remoting.http12.exception.EncodeException;
 import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
@@ -27,7 +26,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
-@Activate(onClass = "com.google.protobuf.Message")
 public class ProtobufHttpMessageCodec implements HttpMessageCodec {
 
     private static final MediaType MEDIA_TYPE = new MediaType("application", 
"x-protobuf");
@@ -51,7 +49,7 @@ public class ProtobufHttpMessageCodec implements 
HttpMessageCodec {
     }
 
     @Override
-    public MediaType contentType() {
+    public MediaType mediaType() {
         return MEDIA_TYPE;
     }
 }
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/WrapperHttpMessageCodec.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/WrapperHttpMessageCodec.java
index ea68580736..907f01cd30 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/WrapperHttpMessageCodec.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/grpc/WrapperHttpMessageCodec.java
@@ -129,7 +129,7 @@ public class WrapperHttpMessageCodec implements 
HttpMessageCodec {
     }
 
     @Override
-    public MediaType contentType() {
+    public MediaType mediaType() {
         return MEDIA_TYPE;
     }
 
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java
index 2253fb6e22..389e48bac3 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http1/DefaultHttp11ServerTransportListener.java
@@ -26,7 +26,7 @@ import 
org.apache.dubbo.remoting.http12.h1.Http1ServerChannelObserver;
 import org.apache.dubbo.remoting.http12.h1.Http1ServerStreamChannelObserver;
 import org.apache.dubbo.remoting.http12.h1.Http1ServerTransportListener;
 import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
+import org.apache.dubbo.remoting.http12.message.HttpMessageDecoder;
 import org.apache.dubbo.remoting.http12.message.ListeningDecoder;
 import org.apache.dubbo.remoting.http12.message.MediaType;
 import org.apache.dubbo.remoting.http12.message.MethodMetadata;
@@ -60,12 +60,16 @@ public class DefaultHttp11ServerTransportListener
         switch (methodDescriptor.getRpcType()) {
             case UNARY:
                 Http1ServerChannelObserver http1ChannelObserver = new 
Http1ServerChannelObserver(httpChannel);
-                
http1ChannelObserver.setHttpMessageCodec(getHttpMessageCodec());
+                http1ChannelObserver.setResponseEncoder(getCodecUtils()
+                        .determineHttpMessageEncoder(
+                                getFrameworkModel(), 
getHttpMetadata().headers(), getUrl()));
                 return new AutoCompleteUnaryServerCallListener(invocation, 
invoker, http1ChannelObserver);
             case SERVER_STREAM:
                 Http1ServerChannelObserver serverStreamChannelObserver =
                         new Http1ServerStreamChannelObserver(httpChannel);
-                
serverStreamChannelObserver.setHttpMessageCodec(getHttpMessageCodec());
+                serverStreamChannelObserver.setResponseEncoder(getCodecUtils()
+                        .determineHttpMessageEncoder(
+                                getFrameworkModel(), 
getHttpMetadata().headers(), getUrl()));
                 serverStreamChannelObserver.setHeadersCustomizer((headers) -> 
headers.set(
                         HttpHeaderNames.CONTENT_TYPE.getName(), 
MediaType.TEXT_EVENT_STREAM_VALUE.getName()));
                 return new 
AutoCompleteServerStreamServerCallListener(invocation, invoker, 
serverStreamChannelObserver);
@@ -87,14 +91,13 @@ public class DefaultHttp11ServerTransportListener
         setMethodDescriptor(methodDescriptor);
         setMethodMetadata(methodMetadata);
         setRpcInvocation(rpcInvocation);
-        HttpMessageCodec httpMessageCodec = getHttpMessageCodec();
         ListeningDecoder listeningDecoder =
-                newListeningDecoder(httpMessageCodec, 
methodMetadata.getActualRequestTypes());
+                newListeningDecoder(getHttpMessageDecoder(), 
methodMetadata.getActualRequestTypes());
         return new DefaultHttpMessageListener(listeningDecoder);
     }
 
-    private ListeningDecoder newListeningDecoder(HttpMessageCodec codec, 
Class<?>[] actualRequestTypes) {
-        DefaultListeningDecoder defaultListeningDecoder = new 
DefaultListeningDecoder(codec, actualRequestTypes);
+    private ListeningDecoder newListeningDecoder(HttpMessageDecoder decoder, 
Class<?>[] actualRequestTypes) {
+        DefaultListeningDecoder defaultListeningDecoder = new 
DefaultListeningDecoder(decoder, actualRequestTypes);
         ServerCallListener serverCallListener = 
startListener(getRpcInvocation(), getMethodDescriptor(), getInvoker());
         defaultListeningDecoder.setListener(serverCallListener::onMessage);
         return defaultListeningDecoder;
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java
index c4b4f46007..a859ae48ae 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/GenericHttp2ServerTransportListener.java
@@ -27,7 +27,6 @@ import org.apache.dubbo.remoting.http12.h2.Http2InputMessage;
 import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver;
 import org.apache.dubbo.remoting.http12.h2.Http2TransportListener;
 import org.apache.dubbo.remoting.http12.message.DefaultListeningDecoder;
-import org.apache.dubbo.remoting.http12.message.JsonCodec;
 import org.apache.dubbo.remoting.http12.message.ListeningDecoder;
 import org.apache.dubbo.remoting.http12.message.MethodMetadata;
 import org.apache.dubbo.remoting.http12.message.NoOpStreamingDecoder;
@@ -71,7 +70,6 @@ public class GenericHttp2ServerTransportListener extends 
AbstractServerTransport
                 .getExecutorSupport(url);
         this.streamingDecoder = newStreamingDecoder();
         this.serverChannelObserver = new 
Http2ServerCallToObserverAdapter(frameworkModel, h2StreamChannel);
-        this.serverChannelObserver.setHttpMessageCodec(JsonCodec.INSTANCE);
         this.serverChannelObserver.setStreamingDecoder(streamingDecoder);
     }
 
@@ -154,7 +152,7 @@ public class GenericHttp2ServerTransportListener extends 
AbstractServerTransport
         }
         initializeServerCallListener();
         DefaultListeningDecoder defaultListeningDecoder = new 
DefaultListeningDecoder(
-                getHttpMessageCodec(), 
getMethodMetadata().getActualRequestTypes());
+                getHttpMessageDecoder(), 
getMethodMetadata().getActualRequestTypes());
         defaultListeningDecoder.setListener(new 
Http2StreamingDecodeListener(serverCallListener));
         streamingDecoder.setFragmentListener(new 
StreamingDecoder.DefaultFragmentListener(defaultListeningDecoder));
         getServerChannelObserver().setStreamingDecoder(streamingDecoder);
@@ -164,7 +162,8 @@ public class GenericHttp2ServerTransportListener extends 
AbstractServerTransport
     @Override
     protected void onMetadataCompletion(Http2Header metadata) {
         super.onMetadataCompletion(metadata);
-        this.serverChannelObserver.setHttpMessageCodec(getHttpMessageCodec());
+        this.serverChannelObserver.setResponseEncoder(
+                
getCodecUtils().determineHttpMessageEncoder(getFrameworkModel(), 
metadata.headers(), getUrl()));
         this.serverChannelObserver.request(1);
     }
 
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java
index 8460ee3df1..7a0f96c282 100644
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/h12/http2/Http2ServerStreamObserver.java
@@ -20,13 +20,12 @@ import org.apache.dubbo.remoting.http12.HttpHeaders;
 import org.apache.dubbo.remoting.http12.HttpMetadata;
 import org.apache.dubbo.remoting.http12.h2.H2StreamChannel;
 import org.apache.dubbo.remoting.http12.h2.Http2ServerChannelObserver;
-import org.apache.dubbo.remoting.http12.message.HttpMessageCodec;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 import org.apache.dubbo.rpc.protocol.tri.ServerStreamObserver;
 import org.apache.dubbo.rpc.protocol.tri.TripleProtocol;
 import org.apache.dubbo.rpc.protocol.tri.compressor.Compressor;
 import org.apache.dubbo.rpc.protocol.tri.h12.AttachmentHolder;
-import org.apache.dubbo.rpc.protocol.tri.h12.CompressibleCodec;
+import org.apache.dubbo.rpc.protocol.tri.h12.CompressibleEncoder;
 import org.apache.dubbo.rpc.protocol.tri.stream.StreamUtils;
 
 import java.util.Map;
@@ -36,8 +35,6 @@ public class Http2ServerStreamObserver extends 
Http2ServerChannelObserver
 
     private final FrameworkModel frameworkModel;
 
-    private HttpMessageCodec httpMessageCodec;
-
     private Map<String, Object> attachments;
 
     public Http2ServerStreamObserver(FrameworkModel frameworkModel, 
H2StreamChannel h2StreamChannel) {
@@ -47,15 +44,9 @@ public class Http2ServerStreamObserver extends 
Http2ServerChannelObserver
 
     @Override
     public void setCompression(String compression) {
-        CompressibleCodec compressibleCodec = new 
CompressibleCodec(httpMessageCodec);
-        
compressibleCodec.setCompressor(Compressor.getCompressor(frameworkModel, 
compression));
-        super.setHttpMessageCodec(compressibleCodec);
-    }
-
-    @Override
-    public void setHttpMessageCodec(HttpMessageCodec httpMessageCodec) {
-        super.setHttpMessageCodec(httpMessageCodec);
-        this.httpMessageCodec = httpMessageCodec;
+        CompressibleEncoder compressibleEncoder = new 
CompressibleEncoder(getResponseEncoder());
+        
compressibleEncoder.setCompressor(Compressor.getCompressor(frameworkModel, 
compression));
+        super.setResponseEncoder(compressibleEncoder);
     }
 
     @Override
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodec
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodec
deleted file mode 100644
index 388cbd7e3e..0000000000
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodec
+++ /dev/null
@@ -1,2 +0,0 @@
-grpc=org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcCompositeCodec
-protobuf=org.apache.dubbo.rpc.protocol.tri.h12.grpc.ProtobufHttpMessageCodec
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory
deleted file mode 100644
index 39350a2c21..0000000000
--- 
a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageCodecFactory
+++ /dev/null
@@ -1 +0,0 @@
-grpc=org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcCompositeCodecFactory
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
new file mode 100644
index 0000000000..571f146447
--- /dev/null
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageDecoderFactory
@@ -0,0 +1 @@
+composite=org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcCompositeCodecFactory
\ No newline at end of file
diff --git 
a/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
 
b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
new file mode 100644
index 0000000000..571f146447
--- /dev/null
+++ 
b/dubbo-rpc/dubbo-rpc-triple/src/main/resources/META-INF/dubbo/internal/org.apache.dubbo.remoting.http12.message.HttpMessageEncoderFactory
@@ -0,0 +1 @@
+composite=org.apache.dubbo.rpc.protocol.tri.h12.grpc.GrpcCompositeCodecFactory
\ No newline at end of file

Reply via email to