diff --git a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/RestClientRequestImpl.java b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/RestClientRequestImpl.java index 2ca0701b06..2449623019 100644 --- a/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/RestClientRequestImpl.java +++ b/common/common-rest/src/main/java/org/apache/servicecomb/common/rest/codec/param/RestClientRequestImpl.java @@ -32,7 +32,6 @@ import javax.servlet.http.Part; import javax.ws.rs.core.MediaType; -import com.google.common.annotations.VisibleForTesting; import org.apache.servicecomb.common.rest.codec.RestClientRequest; import org.apache.servicecomb.common.rest.codec.RestObjectMapperFactory; import org.apache.servicecomb.foundation.common.utils.PartUtils; @@ -44,6 +43,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; @@ -63,7 +63,7 @@ public class RestClientRequestImpl implements RestClientRequest { protected AsyncResponse asyncResp; @VisibleForTesting - final Multimap uploads = ArrayListMultimap.create(); + protected Multimap uploads; protected HttpClientRequest request; @@ -101,8 +101,11 @@ public Buffer getBodyBuffer() throws Exception { @Override @SuppressWarnings("unchecked") public void attach(String name, Object partOrList) { + if (uploads == null) { + uploads = ArrayListMultimap.create(); + } + if (null == partOrList) { - LOGGER.debug("null file is ignored, file name = [{}]", name); return; } @@ -126,7 +129,7 @@ public void attach(String name, Object partOrList) { public Future end() { writeCookies(); - if (!uploads.isEmpty()) { + if (uploads != null) { return doEndWithUpload(); } diff --git a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java index 87abba9226..be86969fd3 100644 --- a/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java +++ b/common/common-rest/src/test/java/org/apache/servicecomb/common/rest/codec/param/TestRestClientRequestImpl.java @@ -161,6 +161,7 @@ public void doEndWithUploadForJre8() { try (MockedStatic mockedStatic = Mockito.mockStatic(UUID.class)) { mockedStatic.when(UUID::randomUUID).thenReturn(uuid); RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, context, null); + restClientRequest.attach("file", null); restClientRequest.doEndWithUpload(); Assertions.assertEquals("multipart/form-data; charset=UTF-8; boundary=boundarynull-null-null-null-null", @@ -181,6 +182,7 @@ public void doEndWithUploadAfterJre8() { try (MockedStatic mockedStatic = Mockito.mockStatic(UUID.class)) { mockedStatic.when(UUID::randomUUID).thenReturn(uuid); RestClientRequestImpl restClientRequest = new RestClientRequestImpl(request, context, null); + restClientRequest.attach("file", null); restClientRequest.doEndWithUpload(); Assertions.assertEquals("multipart/form-data; charset=UTF-8; boundary=boundary00000000-0000-0000-0000-000000000000", diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/UploadDownloadSchemaTest.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/UploadDownloadSchemaTest.java new file mode 100644 index 0000000000..60f61f1c55 --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-client/src/main/java/org/apache/servicecomb/springboot/springmvc/client/UploadDownloadSchemaTest.java @@ -0,0 +1,69 @@ +/* + * 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.servicecomb.springboot.springmvc.client; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.servicecomb.demo.CategorizedTestCase; +import org.apache.servicecomb.demo.TestMgr; +import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestOperations; + +@Component +public class UploadDownloadSchemaTest implements CategorizedTestCase { + RestOperations restOperations = RestTemplateBuilder.create(); + + @Override + public void testRestTransport() throws Exception { + testEmptyFileUploadWork(); + testNonEmptyFileUploadWorkd(); + } + + private void testNonEmptyFileUploadWorkd() throws Exception { + String file2Content = " bonjour"; + File someFile = File.createTempFile("upload2", ".txt"); + FileUtils.writeStringToFile(someFile, file2Content, StandardCharsets.UTF_8, false); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + Map params = new HashMap<>(); + params.put("name", "test"); + params.put("file", someFile); + HttpEntity> entity = new HttpEntity<>(params, headers); + String url = "servicecomb://springmvc/up/down/upload"; + String result = restOperations.postForObject(url, entity, String.class); + TestMgr.check("test; bonjour", result); + } + + private void testEmptyFileUploadWork() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + Map params = new HashMap<>(); + params.put("name", "test"); + HttpEntity> entity = new HttpEntity<>(params, headers); + String url = "servicecomb://springmvc/up/down/upload"; + String result = restOperations.postForObject(url, entity, String.class); + TestMgr.check("test;", result); + } +} diff --git a/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/UploadDownloadSchema.java b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/UploadDownloadSchema.java new file mode 100644 index 0000000000..4c4cd0df5e --- /dev/null +++ b/demo/demo-spring-boot-transport/demo-spring-boot-springmvc-server/src/main/java/org/apache/servicecomb/springboot/springmvc/server/UploadDownloadSchema.java @@ -0,0 +1,48 @@ +/* + * 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.servicecomb.springboot.springmvc.server; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.io.IOUtils; +import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + + +@RestSchema(schemaId = "UploadDownloadSchema") +@RequestMapping(path = "/up/down") +public class UploadDownloadSchema { + @PostMapping(path = "/upload", consumes = MediaType.MULTIPART_FORM_DATA) + public String fileUpload(@RequestPart MultipartFile file, @RequestPart(value = "name") String name) throws Exception { + StringBuilder result = new StringBuilder(); + result.append(name).append(";"); + if (file == null || file.isEmpty()) { + return result.toString(); + } + try (InputStream is = file.getInputStream()) { + result.append(IOUtils.toString(is, StandardCharsets.UTF_8)); + } + return result.toString(); + } +} diff --git a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java index e843836811..b90f6762df 100644 --- a/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java +++ b/demo/demo-springmvc/springmvc-server/src/main/java/org/apache/servicecomb/demo/springmvc/server/ProducerTestsAfterBootup.java @@ -93,7 +93,7 @@ public void testRegisteredBasePath() { if (DynamicPropertyFactory.getInstance().getBooleanProperty("servicecomb.test.vert.transport", true).get()) { TestMgr.check(22, RegistrationManager.INSTANCE.getMicroservice().getPaths().size()); } else { - TestMgr.check(23, RegistrationManager.INSTANCE.getMicroservice().getPaths().size()); + TestMgr.check(24, RegistrationManager.INSTANCE.getMicroservice().getPaths().size()); } } diff --git a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java index 526b4ec993..75da6ded4b 100644 --- a/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java +++ b/transports/transport-rest/transport-rest-client/src/main/java/org/apache/servicecomb/transport/rest/client/RestClientRequestParametersImpl.java @@ -108,15 +108,14 @@ public Multimap getUploads() { @SuppressWarnings("unchecked") @Override public void attach(String name, Object partOrList) { - if (partOrList == null) { - LOGGER.debug("null file is ignored, file name = [{}]", name); - return; - } - if (uploads == null) { uploads = ArrayListMultimap.create(); } + if (partOrList == null) { + return; + } + if (partOrList.getClass().isArray()) { for (Object part : (Object[]) partOrList) { uploads.put(name, PartUtils.getSinglePart(name, part));