How to receive multipart file upload using reactor-netty (without Spring)? - reactor-netty

I've seen there is exemples with reactor-netty on how to post files using multipart form (https://github.com/reactor/reactor-netty/blob/89796a1839a1439a1800424e130515357a827392/src/test/java/reactor/netty/http/client/HttpClientTest.java#L337)
But I couldn't find any information on how to write a server using reactor-netty that can parse multipart information.
It seems that netty is able to do it using HttpPostRequestDecoder class but I cannot see where it fits...
I also seen InterfaceHttpData is a mother class of Attributes and FileUpload but I don't see where I can obtain these objects from the request...
Has anyone ever done this? Any clues?
Thanks a lot

request.receive()
.aggregate()
.flatMap(byteBuf -> {
FullHttpRequest dhr = new DefaultFullHttpRequest(request.version(), request.method(), request.uri(), byteBuf, request.requestHeaders(), EmptyHttpHeaders.INSTANCE);
HttpPostRequestDecoder postDecoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), dhr, CharsetUtil.UTF_8);
// loop data
for (InterfaceHttpData data : postDecoder.getBodyHttpDatas()) {
// attribute
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
// (MemoryAttribute) data
}
// upload
else if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
// (MemoryFileUpload) data
}
}
postDecoder.destroy();
dhr.release();
});

Related

How to mock a multipart file upload when using Spring and Apache File Upload

The project I'm working on needs to support large file uploads and know the time taken during their upload.
To handle the large files I'm using the streaming API of Apache FileUpload, this also allows me to measure the time taken for the complete stream to be saved.
The problem I'm having is that I cannot seem to be able to utilise MockMvc in an Integration Test on this controller. I know that the controller works as I've successfully uploaded files using postman.
Simplified Controller Code:
#PostMapping("/upload")
public String handleUpload(HttpServletRequest request) throws Exception {
ServletFileUpload upload = new ServletFileUpload();
FileItemIterator iterStream = upload.getItemIterator(request);
while (iterStream.hasNext()) {
FileItemStream item = iterStream.next();
String name = item.getFieldName();
InputStream stream = item.openStream();
if (!item.isFormField()) {
// Process the InputStream
} else {
String formFieldValue = Streams.asString(stream);
}
}
}
Simplified Test Code:
private fun uploadFile(tfr: TestFileContainer) {
val mockFile = MockMultipartFile("file", tfr.getData()) // .getData*() returns a ByteArray
val receiveFileRequest = MockMvcRequestBuilders.multipart("/upload")
.file(mockFile)
.contentType(MediaType.MULTIPART_FORM_DATA)
val result = mockMvc.perform(receiveFileRequest)
.andExpect(status().isCreated)
.andExpect(header().exists(LOCATION))
.andReturn(
}
This is the error I'm currently getting
org.apache.tomcat.util.http.fileupload.FileUploadException: the
request was rejected because no multipart boundary was found
Can anyone help?
The MockMultipartFile approach won't work as Spring does work behind the scenes and simply passes the file around.
Ended up using RestTemplate instead as it actually constructs requests.

MvcRazorToPdf How to download file using ajax call? MVC

I tried to use MvcRazorToPdf, i can able to generate mail merge letters. My aim is after downloading file i want to return json message from controller. how to do?
Controller: [how to convert the below lines to generate pdf and download without return]
return new PdfActionResult(pdfres, (writer, document) =>
{
document.SetPageSize(new Rectangle(PageSize.A4));
document.NewPage();
})
{
FileDownloadName = "ElanWasHere.pdf"
};
I appreciate your help. thanks

Compression response filter fails on breeze.js Metadata call

I have an http module where I'm adding a response filter below for compression. This works for all API calls except for 1, the call to MetaData. If I remove the [BreezeController] decoration it works fine. I think it has to do with action filter attribute that converts the string return type into an HttpResponse return type with string content.
The error I'm getting is " Exception message: The stream state of the underlying compression routine is inconsistent."
I've done some testing where a method thats defined to return an HttpResponse works fine. So I think its the scenario where the method is defined to return string, and then the action filter changes it to HttpResponse at runtime.
Any ideas how I can get this to work?
Here's the response filter being added in BeginRequest:
HttpApplication app = (HttpApplication)sender;
// Check the header to see if it can accept compressed output
string encodings = app.Request.Headers.Get("Accept-Encoding");
if (encodings == null)
return;
Stream s = app.Response.Filter;
encodings = encodings.ToLower();
if (encodings.Contains("gzip"))
{
app.Response.Filter = new GZipStream(s, CompressionMode.Compress);
app.Response.AppendHeader("Content-Encoding", "gzip");
}
Don't know the specifics of what you're doing but I know that the [BreezeController] attribute strips out filters and adds back just the ones that breeze wants.
One approach might be to define a separate controller (ModelMetadataController) that only serves the metadata. This controller doesn't have the [BreezeController] attribute; it's a plain old Web API controller.
Then you create a "Breeze controller" (ModelController) with all of the usual methods except the Metadata method.
You call the metadata controller from the client during app launch via MetadataStore.fetchMetadata just to get metadata.
Once you have populated a metadataStore in this fashion, you use it in your EntityManager which sends query and save requests to the "real" Web API data controller.
The client code might look something like this:
var ds = new breeze.DataService({
serviceName: 'breeze/Model' // the breeze query & save controller
});
var ms = new MetadataStore({
namingConvention: breeze.NamingConvention.camelCase, // assuming that's what you want
});
ms.addDataService(ds); // associate the metadata-to-come with the "real" dataService
var manager = new breeze.EntityManager({
dataService: ds,
metadataStore: ms
});
// the fun bit: fetch the metadata from a different controller
var promise = ms.fetchMetadata('breeze/ModelMetadata') // the metadata-only controller!
return promise; // wait on it appropriately

How can I extract form data from within the ASP.NET Web API OnActionExecuting Filter method

I'm trying to extract form data from within the OnActionExecuting method of an ASP.NET Web API Action Filter so I can write it to a log file.
My code looks like this:
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext ctx)
{
if (ctx.Request.RequestUri.Query.StartsWith("admin/")) return;
try
{
_loggingService.LogRequest(new RequestLogModel
{
Handler = ctx.ControllerContext.ControllerDescriptor.ControllerName,
Uri = ctx.Request.RequestUri.AbsoluteUri,
RequestType = ctx.Request.Method.Method,
RequestFrom = ctx.Request.RequestUri.Host,
QueryString = ctx.Request.RequestUri.Query,
FormData = // Need to get form-data here
});
}
catch { }
I can't seem to work out how to get the form data from the request. Can anyone help?
You should be able to get the form data in the request's content.
For more information on reading the multipart/form-data content using ReadAsMultipartAsync(...), check out this tutorial, Sending HTML Form Data.

how to get a httppostedfile from a ASP.NET Web API (POST or PUT) call?

Actually my question is short.
How can I get a HttpPostedFile from a ASP.NET Web API POST or PUT?
I did see that I can get various information from the Request like Request.Header, Request.Content, Request.Properties. Where in there can I find the file I passed and how can I create a HttpPostedFile from it?
Thanks in advance!
Check out the great article from Henrik Nielsen to post multi-part content (i.e posting a form with file)
UPDATE: Add simple code for a controller to receive a file without multipart content
If you only need your controller to receive a file (i.e. no multipart content), you could do something like the above. The request only contains the file binary and the filename is passed within the URL.
public Task<HttpResponseMessage> Post([FromUri]string filename)
{
Guid uploadedFile = Guid.NewGuid();
Task<HttpResponseMessage> task = Request.Content.ReadAsStreamAsync().ContinueWith<HttpResponseMessage>(t =>
{
if (t.IsFaulted || t.IsCanceled)
throw new HttpResponseException(HttpStatusCode.InternalServerError);
try
{
using (Stream stream = t.Result)
{
//TODO: Write the stream to file system / db as you need
}
}
catch (Exception e)
{
Object o = e;
return Request.CreateResponse(HttpStatusCode.InternalServerError, e.GetBaseException().Message);
}
return Request.CreateResponse(HttpStatusCode.Created, uploadedFile.ToString());
});
return task;
}
Your short question does not have a short answer I am afraid.
ASP.NET Web API exposes you to the wonders of HTTP while ASP.NET MVC abstracted some of it - in this case for HttpPostedFile.
So a bit of background:
HTTP posts where a file is involved usually has multipart form data content. This means that you are mixing different kind of content-type: your normal form data will be sent using formurlencoded while the files will be sent application/octent-stream.
So in Web API, all you have to do is to say
var contents = message.Content.ReadAsMultipartAsync(); // message is HttpRequestMessage
One of the contents will contain your file.

Resources