Skip to content
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

Get uploaded size while upload is in progress #3661

Closed

Conversation

fredericBregier
Copy link
Member

Proposal to fix issue #3636 (this has to be fix in all versions)

Motivations:
Currently, while adding the next buffers to the decoder (decoder.offer()), there is no way to access to the current HTTP object being decoded since it can only be available currently once fully decoded by decoder.hasNext().

Some could want to know the progression on the overall transfer but also per HTTP object.
While overall progression could be done using (if available) the global Content-Length of the request and taking into account each HttpContent size, the per HttpData object progression is unknown.

In addition, currently, the Content-Length is not provided by the client and not taken into account for Attribute.

Modifications:

  1. For HTTP object, AbstractHttpData has 2 protected properties named definedSize and size, respectively the supposely final size and the current (decoded until now) size.
    This provides a new method definedSize() to get the current value for definedSize. The size attribute is reachable by the length() method.

Note however definedSize is only defined if Content-Length is provided (not mandatory). So definedSize might be 0.

  1. In the InterfaceHttpPostRequestDecoder (and the derived classes), I add a new method: decoder.currentPartialHttpData() which will return a InterfaceHttpData (if any) as the current Attribute or FileUpload (the 2 generic types), which will allow then the programmer to check
    according to the real type (instance of) the 2 methods definedSize() and length().

This method check if currentFileUpload or currentAttribute are null and returns the one (only one could be not null) that is not null.

Note that if this method returns null, it might mean 2 situations:
a) the last HttpData (whatever attribute or file upload) is already finished and therefore accessible through next()
b) there is not yet any HttpData in decoding (body not yet parsed for instance)

  1. Add Content-Length in default behavior in Multipart Encoder and handling in Multipart Decoder for Attribute (missing parts).

  2. Add constructor for Attribute and Factory to create Attribute if possible with definedSize.

Result:
The developper has more access and therefore control on the current upload.
The coding from developper side could looks like in the example in HttpUloadServerHandler.

@fredericBregier fredericBregier force-pushed the master-upload-progress branch 2 times, most recently from 6c098ee to 3ce04d5 Compare April 18, 2015 15:36
@fredericBregier
Copy link
Member Author

Additionnal note: it seems we do not send any Content-Length in the encoder. This lead to an unkown final size for the transmitted file (or attribute).
I'm currenlty checking if it is valid to add a Content-Length in the multipart section (not clearly seen as not possible, but neither as possible).
Moreover the example doesn't work since there is no guard on division by definedLength which is 0 yet.

Continue to investigate and if someone has a clue... ;-)

@fredericBregier
Copy link
Member Author

According to RFC2046 chapter 5.1:

The only header fields that have defined meaning for body parts are
those the names of which begin with "Content-".  All other header
fields may be ignored in body parts.

So adding Content-Length to Multipart is valid but not mandatory.

I create another pull request for 3.10 since it is easier for me to test (no need of Groovy to build netty through Eclipse so direct testing is possible). See #3663 from now on, until accepted. Then I will redo the work for master version (and supposesly the same for 4.0 and 4.1 branches).

@fredericBregier
Copy link
Member Author

Note that I am not (yet) able to locally test the Junit since now Netty contains a partial construction of source through Groovy scripts, therefore preventing Eclipse environment to build and run Junit tests.

If someone has an idea how to managed this?

@fredericBregier
Copy link
Member Author

Note for others: I answer myself since I managed finally...
Step 1) from shell, in "common" directory, run "mvn generate-sources"
Step 2) add generated sources in buid path in eclipse project "common/target/generated-sources/collections/java"
Step 3) now Junit runs from Eclipse
Not so clean but functional...
;-)

@fredericBregier
Copy link
Member Author

@normanmaurer @Scottmitch @trustin
Please review (master version, shall be the same for 4.x, while #3663 is for 3.10)

*
* If no Content-Length is provided in the request, this is equivalent to the current size (length()) since the
* decoding does not known the final size yet. Therefore the defined length is
* always 0 the current length (whatever during decoding or in final state).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Therefore the defined length is always 0 the current length (whatever during decoding or in final state).

Can you clarify this. I'm not sure what is always 0 the current length means.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed it is not clear (and maybe even false). Better should be:
If no Content-Length is provided in the request, the defined length is always 0 (whatever during decoding or in final state).

@Scottmitch
Copy link
Member

@fredericBregier - I did a quick first pass. I would need to dig in to absorb this area a bit more...I'm not too familiar with this area of code. Perhaps I'll have more time later this week or this weekend...

@fredericBregier
Copy link
Member Author

@Scottmitch Thanks for this first pass! I've corrected (in better English I hope).
I fix also the output from Server side to log.
I will change the 3.10 accordingly too.

@fredericBregier
Copy link
Member Author

@Scottmitch @normanmaurer ping (and not to forget the 3.10 version #3663 )
I'm currently doing the squash of both...

Proposal to fix issue netty#3636

Motivations:
Currently, while adding the next buffers to the decoder
(`decoder.offer()`), there is no way to access to the current HTTP
object being decoded since it can only be available currently once fully
decoded by `decoder.hasNext()`.
Some could want to know the progression on the overall transfer but also
per HTTP object.
While overall progression could be done using (if available) the global
Content-Length of the request and taking into account each HttpContent
size, the per HttpData object progression is unknown.

Modifications:
1) For HTTP object, `AbstractHttpData` has 2 protected properties named
`definedSize` and `size`, respectively the supposely final size and the
current (decoded until now) size.
This provides a new method `definedSize()` to get the current value for
`definedSize`. The `size` attribute is reachable by the `length()`
method.

Note however there are 2 different ways that currently managed the
`definedSize`:
a) `Attribute`: it is reset each time the value is less than actual
(when a buffer is added, the value is increased) since the final length
is not known (no Content-Length)
b) `FileUpload`: it is set at startup from the lengh provided

So these differences could lead in wrong perception;
a) `Attribute`: definedSize = size always
b) `FileUpload`: definedSize >= size always

Therefore the comment tries to explain clearly the different behaviors.

2) In the InterfaceHttpPostRequestDecoder (and the derived classes), I
add a new method: `decoder.currentPartialHttpData()` which will return a
`InterfaceHttpData` (if any) as the current `Attribute` or `FileUpload`
(the 2 generic types), which will allow then the programmer to check
according to the real type (instance of) the 2 methods `definedSize()`
and `length()`.

This method check if currentFileUpload or currentAttribute are null and
returns the one (only one could be not null) that is not null.

Note that if this method returns null, it might mean 2 situations:
a) the last `HttpData` (whatever attribute or file upload) is already
finished and therefore accessible through `next()`
b) there is not yet any `HttpData` in decoding (body not yet parsed for
instance)

Result:
The developper has more access and therefore control on the current
upload.
The coding from developper side could looks like in the example in
HttpUloadServerHandler.
@fredericBregier
Copy link
Member Author

Note: Jenkins build is ok but returns a bad status for an unrelated reason:

09:51:12 18:24:35.946 [main] ERROR io.netty.util.ResourceLeakDetector - LEAK: DnsMessage.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more information.
09:51:12 Build step 'Jenkins Text Finder' changed build result to FAILURE

@fredericBregier
Copy link
Member Author

@normanmaurer ping (note Jenkins build was ok, the error is unrelated)

@fredericBregier
Copy link
Member Author

@normanmaurer ping ;-) (and #3663 is for 3.10)

@normanmaurer
Copy link
Member

will check tomorrow

On 17 May 2015, at 20:31, Frédéric Brégier notifications@github.com wrote:

@normanmaurer https://github.com/normanmaurer ping ;-) (and #3663 #3663 is for 3.10)


Reply to this email directly or view it on GitHub #3661 (comment).

@normanmaurer
Copy link
Member

@fredericBregier this looks good but we can only do this in 4.1 and master as this will break the HttpData and HttpDataFactory interfaces. What we could do is just not change the interface but only the implementations for 4.0 though. WDYT ?

@normanmaurer
Copy link
Member

@netkins build

@fredericBregier
Copy link
Member Author

@normanmaurer Maybe I made something wrong, but I don't think I break the relative interfaces, but adding some new entries in it (not changing previous ones, as in 3.10 too). Of course, classes already implemented outside Netty based on those interfaces will have to build their own.

Also without changing the interface might be difficult since one has to be able to add a defined size through factory (which doesn't support it without this extension).

One solution could be to add a new setter for definedSize (none at the moment, but I do add a getter). Indeed, as there was no setter, only the constructor was able to set this value (so the extension of the interface). We could create a new setter and then being able to call it after the creation through the factory, but then we still change the API of HttpData with this new setter, so not completely transparent...

Have you other options in mind?

@normanmaurer
Copy link
Member

@fredericBregier that's exactly the problem. We can not add new methods to an interface in a bug fix release.

@fredericBregier
Copy link
Member Author

@normanmaurer OK, so if it is strict, I believe there is no patch to apply to 3.10 and 4.0 since we need at least to add the getter/setter for definedSize and the added method currentPartialHttpData() in InterfaceHttpPostRequestDecoder to fulfill the desired feature since all code relies on those interfaces.

Is that ok to push this only to 4.1/master ? (note that original request from final user seems on master)

@karuturi
Copy link

Hi @fredericBregier ,
I opened this issue. I might have mentioned the version wrong but, I am using 4.0.25.Final currently.
Thanks for fixing this,
Rajani

@fredericBregier
Copy link
Member Author

@normanmaurer By the way, it is not really a bug fix but a feature + an improvement (since Content-Length was ignored before - improvement - and there was no way to address partial data during upload process - new feature - ). I don't see other ways than adding some methods to HttpData and InterfaceHttpPostRequestDecoder (and best also in HttpDataFactory to be consistent).

Have you an idea how to deal with this rule for this case?

@fredericBregier
Copy link
Member Author

@normanmaurer the jenkins build error seems not related to this PR, right?

@trustin
Copy link
Member

trustin commented May 20, 2015

@fredericBregier Right.

@fredericBregier
Copy link
Member Author

@netkins build

@fredericBregier
Copy link
Member Author

Note: the build is still failed but not related to this PR.

@Scottmitch
Copy link
Member

@netkins build

@fredericBregier
Copy link
Member Author

again failed jenkins build not related to this PR

@trustin
Copy link
Member

trustin commented Jun 12, 2015

LGTM.

@normanmaurer
Copy link
Member

Cherry-picked into master (c4d8618) and 4.1 (caa1505)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants