New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handling multipart requests #368
Conversation
Ninja Web Framework » ninja #630 FAILURE |
Ninja Web Framework » ninja #631 SUCCESS |
} | ||
} | ||
} catch (FileUploadException | IOException ex) { | ||
logger.error("Failed to parse multipart request data", ex); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... should we throw the error? So we can fail fast - or just silently ignore that parsing went wrong and log... not 100% sure...
That looks very nice! Obvious stuff missing:
Stuff that we still need to tackle: Stuff you asked: Hope that helps :) Your PR looks really nice. The uploading facilities were really not a nice part of Ninja. But you improved it very very nicely :) Good work! |
…impl Context has two implementations now - the current one and one for multipart requests. Two binding are registered, impl for multipart contexts has additional binding annotation
Ninja Web Framework » ninja #643 FAILURE |
Ninja Web Framework » ninja #644 FAILURE |
Ninja Web Framework » ninja #645 FAILURE |
…art-params Conflicts: ninja-core/src/site/markdown/developer/changelog.md
Updates:
P.S. |
Ninja Web Framework » ninja #646 SUCCESS |
Ninja Web Framework » ninja #647 SUCCESS |
This looks really good - unfortunately we are quite busy right now - so it may take some more days to review and merge :) |
Conflicts: ninja-core/src/site/markdown/developer/changelog.md
Ninja Web Framework » ninja #665 SUCCESS |
Ninja Web Framework » ninja #666 SUCCESS |
Looking now into the PR. Quite a lot of code... So reviewing may take a while :) |
StringBuilder sb = new StringBuilder(); | ||
try (InputStreamReader isr = new InputStreamReader(fileItemStream.openStream())) { | ||
int n; | ||
char[] buf = new char[128]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be replaced by a simple Streams.asString(item.openStream());
before we continue a deeper discussion. Do you think it is possible to incorporate MultipartContextImpl into ContextImpl? That you'd be the first thing I'd try to do - to remove a lot of code and also remove the bridge that checks whether to create a MultipartContextImpl or a ContextImpl. Providing the InputStream feels handy to me... :) |
Ninja Web Framework » ninja #683 SUCCESS |
Conflicts: ninja-core/src/site/markdown/developer/changelog.md
Ninja Web Framework » ninja #697 SUCCESS |
I don't care. We can merge this PR first and then @momiji can submit the improved version. @bazi I got some more remarks (tiny stuff I did not say until the big things were ironed out...) I'll add that now... Once that's incorporated we can merge it into master... :) |
@@ -41,6 +41,8 @@ | |||
interface Impl extends Context { | |||
|
|||
void setRoute(Route route); | |||
|
|||
void cleanup(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we can rename that to cleanupAfterRequest() + add one line of javadoc...
Okay finished adding my smaller remarks. A lot of formatting and language things :) Don't take it personally - it's really just to make things better and keep things uniform across the codebase... |
@bazi Let us know when you are finished - then we can merge the PR :) |
I doubt you can merge my PR after, as it use a very different approach than this one. It will require to remove too many things from this PR, and should be considered as a drop-in replacement. Making my own PR was more a challenge to see if the "file provider" was something that could be done, and I found that it was quite easy to implement. It also make me learn things about Github branching, Mockito tests, Guice injection, and so on. The important thing is to have a way to handle files, whatever way is used to do it, and to do it in a way that let's the final developers do their job, with enough flexibility. I would have only one request before merging this PR, please be sure you do not break getFileItemIterator() current behavior. It may already be used in some applications, and shod still work as before, meaning providing original streams to the developer. I'm just saying that because we are already using it in several 3 different ways:
I doubt to be able to do all that with the new way to handle uploads, as we have both in-memory and disk, but this is not a problem as long as we can still use the getFileItemIterator(), as actually done. If not, then this should be mentioned that this is a breaking change, and we will switch to use the internal httpServletRequest and ServletFileUpload, as it was originally coded. |
Ok - how should we proceed? I don't care how it is implemented as the way it is currently is very very low level (but works of course). Any improvement would be great. The only constraint I have: I want to be able to control whether the file is stored in memory or on disk. Anything else can be discussed :) I guess it is about you two: @bazi @momiji - you did the great job of actually implementing great solutions. Can you agree on one? Or agree on how we want to proceed from those two PRs? Thanks :) |
@momiji Anyways, i made a decision. Let's abandon this PR and focus on the other one from @momiji, guess it is #383 but it seems closed. Please provide PR, I will be on the topic. @raphaelbauer beg your pardon for your time spent on reviewing ;-) |
Absolutely no problem! It's a pleasure to read code and improve things together! :) Cool effort! I'll close this PR then... |
First of all let me note that this PR is not complete yet and needs community's feedback.
What this PR targets
Parameter injection into controller methods does not work yet with
multipart/form-data
requests. This issue was addressed in mail group here where @raphaelbauer proposed to make@Param("...") String param
work with multipart requests and additionally introduce something like@File("...") File file
that directly injects uploaded file into controller's method.Besides, i found an old issue #88 that roughly says to hide commons-upload behind some Ninja API.
Well, this PR is all about those issues.
What's already done
Almost everything to handle multipart requests. There are new annotations
@FileParam
and@FileParams
that can be applied to controller method's parameters. For instance, by adding@FileParam("myfile") File file
into your controller method you have a readyjava.io.File
instance to read uploaded file contents from.Additionally, every form parameter of a multipart request (i.e. those that are not attached files) can be injected by
@Param
annotation.What's not done, issues
Cleanup of uploaded filesWhen multipart request are parsed, uploaded files are locally saved in temp directory. I need your feedback on how to clean up those files.
finalize
method ofContext
implementation(references to files are stored inContext
).What are your suggestions? Can we leave cleanup responsibility to application developers or app administrators? I guess not :)
Commons-uploadWell there are no issues with the library ;) This is more related to issue #88.
Currently to handle file uploads we use
Context.getFileItemIterator()
which returns us an iterator of multipart items aka parts. This is the recommended way of handling parts, it is described in Streaming API. As its name implies parts are streamed and you have to handle them once. In this PR, multipart requests are parsed automatically (i.e. iterator is used) and all related parameters and files are available for injection. SoContext.getFileItemIterator()
becomes useless -- it won't anymore return an iterator that you can iterate through parts.I thought to put
@Deprecated
on that method but deprecated methods shall have their old behavior for migration period but in our case that won't be the case. How hard would migration be if that method is removed?