Should inputstream be closed explicitly when uploading file in jersey multipart? - jersey

I use Jersey multipart to upload file in controller
Here is the typical code case:
#Path("/file")
public class UploadFileService {
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadFile(
#FormDataParam("file") InputStream uploadedInputStream,
#FormDataParam("file") FormDataContentDisposition fileDetail) {
String uploadedFileLocation = "d://uploaded/" + fileDetail.getFileName();
// save it
writeToFile(uploadedInputStream, uploadedFileLocation);
String output = "File uploaded to : " + uploadedFileLocation;
return Response.status(200).entity(output).build();
}
// save uploaded file to new location
private void writeToFile(InputStream uploadedInputStream,
String uploadedFileLocation) {
try {
OutputStream out = new FileOutputStream(new File(
uploadedFileLocation));
int read = 0;
byte[] bytes = new byte[1024];
out = new FileOutputStream(new File(uploadedFileLocation));
while ((read = uploadedInputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have read many example code online, and the inputstream is not closed.
My question is that should I close the uploadedInputStream explicitly or manually? And why?

Related

AWS S3 uploaded file was not shown on cyberduck

I am trying to write an API for uploading and downloading files. After I uploaded a test file, it was not shown on cyberduck, but I can download the test file that I just uploaded.
Then I try to download the file that exist on cyberduck, but it shows
com.emc.object.s3.S3Exception: The specified key does not exist.
API code:
StorageImpl.java
#Service
public class StorageImpl implements Storage {
private static Logger logger = LoggerFactory.getLogger(Storage.class);
#Value("${storage.file.repository}")
private String fileRepository;
#Value("${object.storage.user}")
private String oUser;
#Value("${object.storage.endpoint}")
private String endpoint;
#Value("${object.storage.bucket}")
private String nBucket;
#Value("${object.storage.key.secret}")
private String nSecret;
#Value("${object.storage.region.name}")
private String nRegion;
private S3Client s3client;
public StorageImpl() {
}
#Inject
void init() {
try {
s3client = this.getS3Client();
} catch (Exception e) {
e.printStackTrace();
}
}
private S3Client getS3Client() {
if (s3client == null) {
try {
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, null, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(new PreferredCipherSuiteSSLSocketFactory(sc.getSocketFactory()));
String hostname = "";
URI uri = null;
try {
uri = new URI(endpoint);
hostname = uri.getHost();
} catch (URISyntaxException e) {
logger.error("URL " + endpoint + " is a malformed URL");
e.printStackTrace();
}
S3Config config = null;
config = new S3Config(new URI(endpoint)).withUseVHost(false);
logger.debug("oUser=" + oUser + ", secret=" + nSecret + ", endpoint=" + endpoint);
config.withIdentity(oUser).withSecretKey(nSecret);
logger.debug("");
config.setSignMetadataSearch(true);
s3client = new S3JerseyClient(config, new URLConnectionClientHandler());
logger.debug("s3client initiated. endpoint: " + endpoint);
} catch (Exception ex) {
logger.error(ex.getMessage(), ex);
}
}
return s3client;
}
private File convertMultiPartFileToFile(final MultipartFile multipartFile) {
final File file = new File(multipartFile.getOriginalFilename());
try (final FileOutputStream outputStream = new FileOutputStream(file)) {
outputStream.write(multipartFile.getBytes());
} catch (IOException e) {
logger.error("Error {} occurred while converting the multipart file", e.getLocalizedMessage());
}
return file;
}
#Override
public void save(final MultipartFile multipartFile) {
try {
final File file = convertMultiPartFileToFile(multipartFile);
logger.info("Uploading file with name {}", file.getName());
final PutObjectRequest putObjectRequest = new PutObjectRequest(nBucket, file.getName(), file);
s3client.putObject(putObjectRequest);
Files.delete(file.toPath()); // Remove the file locally created in the project folder
} catch (AmazonServiceException e) {
logger.error("Error {} occurred while uploading file", e.getLocalizedMessage());
} catch (IOException ex) {
logger.error("Error {} occurred while deleting temporary file", ex.getLocalizedMessage());
}catch(S3Exception ae){
ae.printStackTrace();
logger.error("", ae);
}
}
#Override
public InputStream retrieve(String fileName) {
return s3client.getObject(nBucket, fileName).getObject();
}
}
FileController.java
#RestController
#RequestMapping("/files")
#CrossOrigin(origins = "*", maxAge = 3600)
public class FileController {
private static final String MESSAGE_1 = "Uploaded the file successfully";
private static final String FILE_NAME = "fileName";
#Autowired
protected StorageImpl storageImpl;
#Autowired
protected FileService fileService;
#GetMapping
public ResponseEntity<Object> findByName(#RequestParam("fileName") String fileName) {
return ResponseEntity
.ok()
.cacheControl(CacheControl.noCache())
.header("Content-type", "application/octet-stream")
.header("Content-disposition", "attachment; filename=\"" + fileName + "\"")
.body(new InputStreamResource(storageImpl.retrieve(fileName)));
}
#PostMapping
public ResponseEntity<Object> save(#RequestParam("file") MultipartFile multipartFile) {
storageImpl.save(multipartFile);
return new ResponseEntity<>(MESSAGE_1, HttpStatus.OK);
}
}
What are the possible reasons causing this bug?

How to sanitize request object in the #restcontroller

I'm doing a static code analysis using checkmarx, which gave me medium vulnerabilities for #RequestBody.
Will place a sample code below, could someone help me fixing this issue.
#RestController
#RequestMapping("/api")
#Slf4j
#Validated
public class Myclass {
#Autowired
SplitClass split;
#PostMapping(path = "/something", consumes = "application/json", produces = "application/json")
public int splitter(#RequestBody SplitRequestVO **splitReq**) {
int response = 0;
try {
int value = split.methodName(splitReq);
if(value == 1) {
response = 1;
}else {
response = 0;
}
}catch(Exception e) {
log.error("Excpetion in the MY Class controller" +e.getMessage());
}
return response;
}
}
Every time it is showing error with this util class. please check whats wrong in this class.
#Slf4j
public class FileUtil {
private FileUtil() {
throw new IllegalArgumentException("FileUtil.class");
}
public static void createFileFromBytes(String fileName, byte[] bytes) throws IOException {
File file = new File(fileName);
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(bytes);
fos.flush();
} catch (IOException exc) {
log.error("Exception in creating file from bytes : "+exc.getMessage());
}
}
public static void deleteFile(String fileName) {
log.info("Entry into deleteFile method.");
try {
File file = new File(fileName);
if (file.exists()) {
Files.delete(file.toPath());
if (log.isDebugEnabled())
log.debug("file deleted:" + fileName);
}
} catch (Exception e) {
log.error("Exception in deleting the file : "+e.getMessage());
}
log.info("Exit from deleteFile method ");
}
public static byte[] getBytesFromFile(File file) throws IOException {
log.info("Entry into getBytesFromFile method");
byte[] bytes = null;
try (InputStream is = new FileInputStream(file)) {
long length = file.length();
if (length > 2147483647L) {
log.error("File Too large:" + file.getName());
}
bytes = new byte[(int) length];
int offset = 0;
int numRead = 0;
while (offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0)
offset += numRead;
if (offset < bytes.length)
throw new IOException("Could not completely read file " + file.getName());
} catch (Exception e) {
log.error("Exception in getBytesFromFile : "+e.getMessage());
}
log.info("Exit from getBytesFromFile method ");
return bytes;
}
public static byte[] getBytesFromFile(String fileName) throws IOException {
File file = new File(fileName);
return getBytesFromFile(file);
}
}
Here im facing the vulnerability issue to fix in the block letters. Appreciated foy help.
Thanks in advance.

I want to upload file without using multipart in spring boot, would be great if I could get you valuable suggestions on this

Shall I remove this from application.properties
spring.http.multipart.enabled=true
What should be my approach towards this file upload without using multipart?
This way, I'm able to uploading file using where I'm using multipart.
#RequestMapping(value = "/dog/create/{name}", method = RequestMethod.POST)
public JsonNode dogCreation(HttpServletRequest httpRequest, #RequestParam(value = "picture", required = false) MultipartFile multipartFile,
#PathVariable("name") String name) throws IOException, InterruptedException {
JSONObject response = new JSONObject();
Dog dog = new Dog();
String DOG_IMAGES_BASE_LOCATION = "resource\\images\\dogImages";
try {
File file = new File(DOG_IMAGES_BASE_LOCATION);
if (!file.exists()) {
file.mkdirs();
}
} catch (Exception e) {
e.printStackTrace();
}
dog = dogService.getDogByName(name);
if (dog == null) {
if (!multipartFile.isEmpty()) {
String multipartFileName = multipartFile.getOriginalFilename();
String format = multipartFileName.substring(multipartFileName.lastIndexOf("."));
try {
Path path = Paths.get(DOG_IMAGES_BASE_LOCATION + "/" + name + format);
byte[] bytes = multipartFile.getBytes();
File file = new File(path.toString());
file.createNewFile();
Files.write(path, bytes);
if (file.length() == 0) {
response = utility.createResponse(500, Keyword.ERROR, "Image upload failed");
} else {
String dbPath = path.toString().replace('\\', '/');
dog = new Dog();
dog.setName(name);
dog.setPicture(dbPath);
dog = dogService.dogCreation(dog);
response = utility.createResponse(200, Keyword.SUCCESS, "Image upload successful");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return objectMapper.readTree(response.toString());
}
I want to do it without using multipart, what would you suggest?
This is what I've done till now to solve this
#RequestMapping(value = "/dog/create/{name}", method = RequestMethod.POST)
public JsonNode dogCreation(HttpServletRequest httpRequest, #RequestParam("picture") String picture,
#PathVariable("name") String name) throws IOException, InterruptedException {
JSONObject response = new JSONObject();
Dog dog = new Dog();
String DOG_IMAGES_BASE_LOCATION = "resource\\images\\dogImages";
try {
File file = new File(DOG_IMAGES_BASE_LOCATION);
if (!file.exists()) {
file.mkdirs();
}
} catch (Exception e) {
e.printStackTrace();
}
dog = dogService.getDogByName(name);
if (dog == null) {
if (!picture.isEmpty()) {
String dogPicture = picture;
byte[] encodedDogPicture = Base64.encodeBase64(dogPicture.getBytes());
String format = dogPicture.substring(picture.lastIndexOf("."));
try {
} catch (Exception e) {
e.printStackTrace();
}
}
}
return objectMapper.readTree(response.toString());
}
I just have to say that this should probably only be used as a workaround.
On your frontend, convert the file to base64 in js:
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(evt) {
console.log(evt.target.result);
//do POST here - something like this:
$.ajax("/upload64", {
method: "POST",
contentType: "application/text"
data: evt.target.result
}
};
On the server with an example of a decoder - more decoding options here Decode Base64 data in Java
import sun.misc.BASE64Decoder;
#PostMapping("/upload64")
public String uploadBase64(#RequestBody String payload){
BASE64Decoder decoder = new BASE64Decoder();
byte[] decodedBytes = decoder.decodeBuffer(encodedBytes);
//use your bytes
}

Uploading file using Spring REST API

I have my controller like this, i am using POSTMAN REST client for upload pdf file. setting content-type: multipart/form-data;boundary=randomBoundaryNotInAnyOfParts
It is creating the file but not writing anything in it. Am i missing something here?
#RequestMapping(value = "/uploadfile", method = RequestMethod.POST)
public #ResponseBody String upload(HttpServletRequest request) {
InputStream is = null;
OutputStream out = null;
try {
is = request.getInputStream();
byte[] b = new byte[1024];
out = new FileOutputStream(new File("C:\\tmp\\upload.txt"));
out.write(b);
} catch (IOException e) {
e.printStackTrace();
} finally{
try{
if(out != null){
out.close();
}
if(is != null){
is.close();
}
}catch(IOException io){
io.printStackTrace();
}
}
return null;
}
Thanks,
Vinay
Your byte[] is empty hence it is writing nothing in the file. Get content of the request into the byte[] and then write it into file.
Or you can use BufferedWriter also it is more fast.
Thanks,
Brijesh

Spring and serving files from outside of the web server

I want spring to serve certain files from the /tmp... directory, the specific directory isn't determined until shortly after the server starts so using <mvc:resources location="/images/**" mapping="/absolute/path/to/image/dir"/> won't seemingly work.
As Dave Newton noted - stream them from a controller. A very basic implementation:
#RequestMapping("/static/temp/{path}")
public void getResource(#PathVariable path, OutputStream os) {
//TODO proper IO management
InputStream is = new BufferedInputStream(new FileInputStream("/temp/" + path));
IOUtils.copy(is, os);
}
I do something like this:
#RequestMapping(value="/staticFile/{id}", method = RequestMethod.GET)
public void getPhotoRide2(HttpServletResponse response, #PathVariable int id) {
try {
FileInputStream in = new FileInputStream("your file");
OutputStream out = response.getOutputStream();
response.setContentType("your mime type");
byte[] buf = new byte[1024];
int count = 0;
while ((count = in.read(buf)) >= 0) {
out.write(buf, 0, count);
}
in.close();
out.flush();
out.close();
} catch (Exception e) {}
}

Resources