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

Update advice on contentLength() in subclasses of InputStreamResource #20990

Closed
spring-projects-issues opened this issue Jan 31, 2018 · 4 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: task A general task
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Jan 31, 2018

bademus opened SPR-16445 and commented

It seems the bug was introduced in #16633
org.springframework.http.converter.ResourceHttpMessageConverter#getContentLength

// Don't try to determine contentLength on InputStreamResource - cannot be read afterwards...
// Note: custom InputStreamResource subclasses could provide a pre-calculated content length!
if (InputStreamResource.class == resource.getClass()) {
     return null;
}

In fact default behavior of InputStreamResource is not the same as for its children.


Affects: 4.3.14

Issue Links:

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

What specifically are you asking for here? I'm aware that such special handling is unusual but unfortunately there is no sensible way to determine the content length for a plain InputStreamResource. And for custom subclasses thereof, we expect contentLength() to be overridden.

Are you trying to implement such a custom InputStreamResource subclass and expose it to ResourceHttpMessageConverter? In most scenarios, it is preferable to implement a regular Resource with a fresh stream returned from getInputStream(), avoiding the InputStreamResource flaw of dealing with a pre-opened stream.

@spring-projects-issues
Copy link
Collaborator Author

bademus commented

Thanks for quick answer,

Actually I have to subclass InputStreamResource to extend metadata.

I was confused a lot when my application change its behavior after I switch InputStreamResource to MyInputStreamResource.
I got an exceptional cituation because InputStreamResource was read twice on contentLength and on getting inputStream.
I'm thinking about elimination this kind of InputStreamResource behavior if it is possible (I'm aware of legacy background).

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 31, 2018

Juergen Hoeller commented

Before #16633, InputStreamResource itself didn't work with ResourceHttpMessageConverter at all. From that perspective, we at least made that case work. Making it work for InputStreamResource subclasses as well is tough since we don't know whether contentLength() has been overridden there.

So for a custom InputStreamResource subclass, we strongly recommend a custom implementation of contentLength(): possibly simply returning -1, leading to the same behavior as for a standard InputStreamResource in ResourceHttpMessageConverter. I suppose we should at least document that part.

There is indeed a legacy problem here: specifically, that InputStreamResource may be used for content length determination, with contentLength() getting called but not getInputStream() itself. If it wasn't for that specific scenario, we could also let InputStreamResource itself implement contentLength() with a -1 return value.

@spring-projects-issues spring-projects-issues added status: waiting-for-triage An issue we've not yet triaged or decided on type: enhancement A general enhancement in: web Issues in web modules (web, webmvc, webflux, websocket) and removed type: enhancement A general enhancement labels Jan 11, 2019
@rstoyanchev rstoyanchev added status: invalid An issue that we don't feel is valid type: task A general task and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: invalid An issue that we don't feel is valid labels Mar 25, 2020
@rstoyanchev rstoyanchev self-assigned this Mar 25, 2020
@rstoyanchev rstoyanchev added this to the 5.2.6 milestone Mar 25, 2020
@rstoyanchev rstoyanchev changed the title Consistent treatment of InputStreamResource subclasses [SPR-16445] Update advice on contentLength() in subclasses of InputStreamResource Mar 25, 2020
@ger0nimo
Copy link

ger0nimo commented Apr 16, 2020

I encountered the same problem but this code below works for me.

import org.springframework.core.io.ByteArrayResource;
import org.springframework.web.multipart.MultipartFile;

public class MultipartFileResource extends ByteArrayResource {

	private String filename;
	private long contentLength;

	public MultipartFileResource(MultipartFile multipartFile) throws IOException {
		super(multipartFile.getBytes());
		this.filename = multipartFile.getOriginalFilename();
		this.contentLength = multipartFile.getSize();
	}

	@Override
	public String getFilename() {
		return this.filename;
	}
	@Override
	public long contentLength() {
		return this.contentLength;
	}
	 
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: task A general task
Projects
None yet
Development

No branches or pull requests

3 participants