Receive HTTP Stream in Spring Boot - spring

i want to receive a HTTP Stream in SpringBoot but the InputStream of HttpServletRequest seems not to be an endless HTTP Stream and only contains the Content of first HTTP Body.
I want to process a chuncked HTTP Stream in SpringBoot on which is puhed some Value String from time to time.
Currently I tried something like this in a controller:
#Override
public void test(HttpServletRequest request,
HttpServletResponse response) {
System.out.println("StreamStart");
try {
byte[] buffer = new byte[1024];
while(true){
int len = request.getInputStream().read(buffer);
if(len!=-1) {
System.out.println("Len: " + len);
System.out.println(new String(buffer));
}
Thread.sleep(500);
}
}
catch(Exception x){
x.printStackTrace();
}
System.out.println("StreamEnd");
}
However the first Request Body after the header works, but the second does not appear in my Controller.
Does SpringBoot cancles the connection or the stream?
Can I have access to the complete HTTP Input stream to get my values from it?

Maybe Multipart request would be usefull for you?
That way you can recieve multiple parts of data
https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
Example:
#PostMapping("/upload")
public void uploadStream(#RequestParam MultipartFile[] multipartFiles){
for(MultipartFile multipartFile:multipartFiles){
try {
InputStream inputStream = multipartFile.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

Extracting response body in aspect for Spring boot application

I would like to log response body with aspect in my Spring Boot application. As of now, I am doing this as follows:
#Pointcut("within(com.web.rest.*)")
public void applicationResourcePointcut() {
}
#AfterReturning(value = ("applicationResourcePointcut()"),
returning = "returnValue")
public void endpointAfterReturning(JoinPoint joinPoint, Object returnValue) throws Throwable {
try {
System.out.println("RESPONSE OBJECT = " + mapper.writeValueAsString(returnValue));
} catch (JsonProcessingException e) {
System.out.println(e.getMessage());
}
}
But here, I am getting full response with Http Status code and other meta data as follows:
RESPONSE OBJECT = {"headers":{"Location":["/api/students/de7cc0b7-dcdf-4f2e-bc26-41525064dd55"],"X-ThreatModelSvc-Alert":["Entit ystudent is created with id:de7cc0b7-dcdf-4f2e-bc26-41525064dd55"]},"body":{"id":"de7cc0b7-dcdf-4f2e-bc26-41525064dd55","name":"Test Name","description":"Test Description","lastModifiedBy":"amallik"},"statusCodeValue":201,"statusCode":"CREATED"}
Here, I just would like to capture the response body. I cannot understand how to extract just the body from the response.

How to configure Spring DataBuffer size on WebFilter

I'm getting a gzipped content from the client and I need to decompress it before it reaches the controller, otherwise I get a jackson parsing exception.
I created a WebFilter that wraps the request and maps the body into a deflated byte array like this:
#Override
public Flux<DataBuffer> getBody() {
return request.getBody().map(requestDataBuffer -> {
try {
GZIPInputStream gzipInputStream = new GZIPInputStream(requestDataBuffer.asInputStream());
StringWriter writer = new StringWriter();
IOUtils.copy(gzipInputStream, writer, UTF_8);
byte[] targetArray = writer.toString().getBytes();
return new DefaultDataBufferFactory().wrap(targetArray);
}
catch (IOException e) {
LOG.error("failed to create gzip input stream. content-encoding is {}", request.getHeaders().getFirst(CONTENT_ENCODING));
return requestDataBuffer;
}
});
}
However, when the request body is too large the data buffer doesn't contain all the data, therefore I get stream exceptions.
Any ideas how to configure the data buffer or how to accept gzipped content?
I think the best way is to rely on the Netty implementation for that, and configure the server to use that support from Netty.
You can create a component (or return a new instance of this directly from a #Bean method) that customizes the Reactor Netty server:
#Component
public class RequestInflateCustomizer implements NettyServerCustomizer {
#Override
public HttpServer apply(HttpServer httpServer) {
return httpServer.tcpConfiguration(
tcp -> tcp.doOnConnection(conn -> conn.addHandlerFirst(new HttpContentDecompressor())));
}
}

spring : get response as Multipart File from REST WebService

I am creating POC for RESTFUL Web service using Spring 4.0. Requirement is to receive MultipartFile as Response from REST WEB-Service.
REST Service Controller
#RequestMapping(value="/getcontent/file", method=RequestMapping.post)
public MultipartFile getMultipartAsFileAsObject() {
File file = new File("src/test/resources/input.docx");
FileInputStream input = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile("file",file.getName(),
"application/docx", IOUtils.toByteArray(input));
return multipartFile
}
I call this service using third party Clients and Apache Http Client as well. kindly have a look on output.
Using Third party REST client ie. Postman
output looks like Json -
{
"name" : "file",
"originalfilename" : "sample.docx",
"contentType" : "application/docx",
"content" : [
82,
101,
97,
100,
101,
32,
32,
.
.
.
.
.
]
}
Apache HTTP Client Sample code
private static void executeClient() {
HttpClient client = new DefaultHttpClient();
HttpPost postReqeust = new HttpPost(SERVER_URI);
try{
// Set Various Attributes
HttpResponse response = client.execute(postReqeust) ;
//Verify response if any
if (response != null)
{
InputStream inputStream = response.getEntity().getContent();
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
OutputStream outputStream = new FileOutputStream
(new File("src/main/resource/sample.docx"));
outputStream.write(buffer);
outputStream.flush();
outputStream.close();
}
}
catch(Exception ex){
ex.printStackTrace();
}
Output of Apache Http client
file is getting Created but It is empty. (0 bytes).
I found some interesting answers from multiple stackoverflow questions.
Links are given below
file downloading in restful web services
what's the correct way to send a file from REST web service to client?
For Sending single file : (copied from above sources)
#GET
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
File file = ... // Initialize this to the File path you want to serve.
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM)
.header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"" ) //optional
.build();
}
For Sending Zip file : (copied from above sources)
1) Approach First :
You can use above method to send any file / Zip.
private static final String FILE_PATH = "d:\\Test2.zip";
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public Response getFile() {
File file = new File(FILE_PATH);
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=newfile.zip");
return response.build();
}
2) Approach Second :
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_OCTET_STREAM)
public StreamingOutput helloWorldZip() throws Exception {
return new StreamingOutput(){
#Override
public void write(OutputStream arg0) throws IOException, WebApplicationException {
// TODO Auto-generated method stub
BufferedOutputStream bus = new BufferedOutputStream(arg0);
try {
Thread.currentThread().getContextClassLoader().getResource("");
File file = new File("d:\\Test1.zip");
FileInputStream fizip = new FileInputStream(file);
byte[] buffer2 = IOUtils.toByteArray(fizip);
bus.write(buffer2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}

Multipart/form-data and boundary. Need help in streaming the data at server end

I have multipart/form-data request from client side which will upload multiple files. Each file would be a large file (more than 10MB in size). I want to receive each file individually and process it while remaining files are still getting received completely.
This is my request in rest console
URL : http://localhost:8080/multiUpload
Content-Type : multipart/form-data;boundary=myboundary
form-data : two attachments
This is my snippet of code to handle it.
#RequestMapping(value = "/multiUpload", method = RequestMethod.POST)
public #ResponseBody String handleMultiFileUpload(HttpServletRequest request)
throws IOException {
System.out.println("======Inside handleFileUpload======");
try {
MultipartStream multipartStream = new MultipartStream(
request.getInputStream(), "myboundary".getBytes(),
1024 * 1024, null);
boolean nextPart = multipartStream.skipPreamble();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
while (nextPart) {
System.out.println("inside while");
multipartStream.readBodyData(outputStream);
InputStream inputStream = new ByteArrayInputStream(
outputStream.toByteArray());
nextPart = multipartStream.readBoundary();
}
} catch (MultipartStream.MalformedStreamException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "You successfully uploaded !";
}
The code is not entering into while loop. i.e skipPreamble is returning false. Am I doing anything wrong ??.

Sending pdf/doc/txt/image files with JAXWS/cxf services Spring

Can someone provide me a demo of sending pdf files as response ?
Endpoint is
#GET
#Path("/PDFiles")
#WebMethod(operationName = "PDFiles")
public Response pdfiles() {
LOGGER.info("Getting FPodAUMFile.");
return dao.getPDFfiles(CacheKeys.pdffile);
}
DAO would be
public Response getPDFfiles(String pdffile) {
File file_pdf = new File("D:/pdffile.pdf");
// HELP ME SEND THIS PDFFILE.PDF AND COMPLETE THE CODE HERE
}
MTOM Simplifies the way it is sent. Can someone elaborate on using MTOM also ?
You need to specify Content-Disposition header in your response and write the file into the response entity. So for e.g.:
public Response getPDFfiles(String pdffile) {
File filePdf = new File("D:/pdffile.pdf"); //You'll need to convert your file to byte array.
ContentDisposition contentDisposition = new ContentDisposition("attachment;filename=pdffile.pdf");
return Response.ok(
new StreamingOutput() {
#Override
public void write(OutputStream outputStream) throws IOException, WebApplicationException {
outputStream.write(/* Your file contents as byte[] */);
}
})
.header("Content-Disposition", contentDisposition.toString())
.header("Content-Type", "application/pdf")
.build();
}
How to convert a file to byte[] can by found here.

Resources