I want to delete file from server using http doDelete() method - java

if i want to delete welcome.html file how to delete it using http doDelete() methode how to do it i am new to java so plz help me
public void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
boolean success = false;
File file = null;
try {
file = searchFile(request);
} catch (Exception ex) {
java.util.logging.Logger.getLogger(Request.class.getName()).
log(java.util.logging.Level.SEVERE, null, ex);
}
if (!file.exists()) {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
} else {
success = file.delete(); // actual delete operation
}
if (success) {
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
}
}
private String searchFile(HttpServletRequest req) throws Exception {
String fileName = req.getPathInfo();
fileName = fileName.substring(1);
return fileName;
}

While we wait for you to explain how your code "doesn't work" ... I should point out that if this code did work, it would be extremely dangerous.
Your code makes no attempt to check that the user (i.e. the guy sending the request) should be allowed to delete the file, or what the user is attempting to delete. If some bad guy sent you a DELETE request with ".."'s in it, they could probably trick your web server into attempting to delete any file in the file system!!! (Hopefully you never run your web servers as "root" ...)
UPDATE: The answer to your Question is simple. Change
file = searchFile(request);
to
file = new File(searchFile(request));
But that is the least of your problems!

Related

Spring Boot file upload issue - Could not store the file error only occur after few days

I have a RESTful API created using Java Spring Boot 2.4.2.
1 of the main issue that I encountered recently is that, the Multipart file upload is working fine but the same code will not work after couple of days. It will work back after restarted the RESTFul JAR application.
The error that been display in Postman:
Could not store the file. Error
The relevant code to this is here:
try {
FileUploadUtil.saveFile(uploadPath, file.getOriginalFilename(), file);
} catch (IOException e) {
throw new RuntimeException("Could not store the file. Error: " + e.getMessage());
}
And the FileUploadUtil class:
public class FileUploadUtil {
public static void saveFile(String uploadDir, String fileName, MultipartFile multipartFile) throws IOException {
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
try (InputStream inputStream = multipartFile.getInputStream()) {
Path filePath = uploadPath.resolve(fileName);
Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ioe) {
throw new IOException("Could not save uploaded file: " + fileName, ioe);
}
}
public static File fileFor(String uploadDir, String id) {
return new File(uploadDir, id);
}}
And the main POST API method head that called the first part of the code above is:
#PostMapping(value = "/clients/details/{clientDetailsId}/files/{department}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
#PreAuthorize("hasAuthority('PERSONNEL') or hasAuthority('CUSTODIAN') or hasAuthority('ADMIN')")
public ResponseEntity<ClientDetails> createClientDetailsFiles(#PathVariable("clientDetailsId") long clientDetailsId,
#PathVariable("department") String department,
#RequestPart(value = "FORM_SEC_58", required = false) MultipartFile[] FORM_SEC_58_file,#RequestPart(value = "FORM_SEC_78", required = false) MultipartFile[] FORM_SEC_78_file,
#RequestPart(value = "FORM_SEC_105", required = false) MultipartFile[] FORM_SEC_105_file,
#RequestPart(value = "FORM_SEC_51", required = false) MultipartFile[] FORM_SEC_51_file,
#RequestPart(value = "FORM_SEC_76", required = false) MultipartFile[] FORM_SEC_76_file)
And the application.properties side:
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=90MB
spring.servlet.multipart.max-request-size=90MB
Can anyone advise what is the issue ya?
I had the same issue, it was working file once, but after some time, it stopped working. I am almost certain your issue is this, because, we have the same code and our scenario is the same. The way I figured it out was:
Debugging
I added a statement to print the error to see what was actually going on, what you are currently doing is only taking message of error, not the whole error. So change it to:
try {
FileUploadUtil.saveFile(uploadPath, file.getOriginalFilename(), file);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Could not store the file. Error: " + e.getMessage());
}
Actual Problem
And the error was FileAlreadyExistsException FileAlreadyExistsException
Basically what that means is that you are trying to upload a file with same name twice.
Solution
To fix this issue you can use different approaches. One of them is to generate UUID for file and store it also in database, to access later.

Is my file saving logic correct?

My java app calls a rest endpoint and in the response body is a 10GB XML file. Before I send the rest quest, I ask the service how many records will be in the file. I then retrieve the file. When I run my app, the file is saved successfully but only roughly 50% of the expected records. There are 2 reasons the file doesn't have all the records:
The file sent from the rest endpoint only has 50% of the expected records
My app is falling over when before it has finished downloading
My question is, if in scenario 2 and my app falls over, would I see an exception stating so? I do not see an exception, in fact, I see my log statement after the save is saved saying 'File successfully saved'.
EDIT: I have downloaded the file outside of my app, via a curl request and the same thing happened - only 50% of the expected population was downloaded. This proves the issue isn't with my file-saving logic.
public void saveFile() {
try {
downloadAndSaveFile();
} catch (Exception e) {
LOGGER.error("A error has occurred processing all content, caused by {}", e.getMessage(), e);
throw new RuntimeException(e);
}
}
private void downloadAndSaveFile() throws Exception {
long recordCount = countRecords();
LOGGER.info("Number of records to process is {}", recordCount);
if (recordCount > 0 ) {
InputStream dataToSave = getAllContent();
saveStream(dataToSave);
LOGGER.info("File successfully saved.");
} else {
LOGGER.error("No content to retrieve");
throw new RuntimeException("There are no records to process");
}
}
public InputStream getAllContent() throws Exception {
return callRestEndpoint(webTarget).readEntity(InputStream.class);
}
private Response callRestEndpoint(WebTarget target) throws InterruptedException {
Response response = null;
for (int numberOfTries = 0; numberOfTries < reconnectRetries; numberOfTries++) {
try {
response = makeGetRequest(target);
if (OK.getStatusCode() == response.getStatus()) {
break;
}
} catch (Exception ex) {
retryRequest(numberOfTries, ex);
}
}
return response;
}
public void saveStream(InputStream inputStream) throws IOException {
File fileToCreate = new File(fileName);
if (!fileToCreate.exists()) {
fileToCreate.mkdirs();
}
Files.copy(
inputStream,
fileToCreate.toPath(),
StandardCopyOption.REPLACE_EXISTING
);
closeQuietly(inputStream);
}
Is my file saving logic correct?
No.
if (!fileToCreate.exists()) {
fileToCreate.mkdirs();
}
Here you are creating every element in fileToCreate as a directory, including the final element. So trying to open it later as a file will fail. And the exists() test is pointless. It should be:
fileToCreate.getParentFile().mkdirs();
if in scenario 2 and my app falls over, would I see an exception stating so
Yes, provided you print or log it somewhere. The method will definitely throw one.

Download files with netty

I am creating a very basic webserver using netty and java. I will have basic functionality. It's main responsibilities would be to serve responses for API calls done from a client (e.g a browser, or a console app I am building) in JSON form or send a zip file. For that reason I have created the HttpServerHanddler class which is responsible for getting the request, parsing it to find the command and call the appropriate api call.It extends SimpleChannelInboundHandler
and overrides the following functions;
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
LOG.debug("channelActive");
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
LOG.debug("In channelComplete()");
ctx.flush();
}
#Override
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws IOException {
ctx = processMessage(ctx, msg);
if (!HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}
}
private ChannelHandlerContext processMessage(ChannelHandlerContext ctx, Object msg){
if (msg instanceof HttpRequest) {
HttpRequest request = this.request = (HttpRequest) msg;
if (HttpHeaders.is100ContinueExpected(request)) {
send100Continue(ctx);
}
//parse message to find command, parameters and cookies
ctx = executeCommand(command, parameters, cookies)
}
if (msg instanceof LastHttpContent) {
LOG.debug("msg is of LastHttpContent");
if (!HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}
}
return ctx;
}
private ChanndelHandlerContext executeCommand(String command, HashMap<String, List<String>>> parameters, Set<Cookie> cookies>){
//switch case to see which command has to be invoked
switch(command){
//many cases
case "/report":
ctx = myApi.getReport(parameters, cookies); //This is a member var of ServerHandler
break;
//many more cases
}
return ctx;
}
In my Api class that has the getReport function.
getReport
public ChannelHandlerContext getReportFile(Map<String, List<String>> parameters,
Set<Cookie> cookies) {
//some initiliazations. Actual file handing happens bellow
File file = new File(fixedReportPath);
RandomAccessFile raf = null;
long fileLength = 0L;
try {
raf = new RandomAccessFile(file, "r");
fileLength = raf.length();
LOG.debug("creating response for file");
this.response = Response.createFileResponse(fileLength);
this.ctx.write(response);
this.ctx.write(new HttpChunkedInput(new ChunkedFile(raf, 0,
fileLength,
8192)),
this.ctx.newProgressivePromise());
} catch (FileNotFoundException fnfe) {
LOG.debug("File was not found", fnfe);
this.response = Response.createStringResponse("failure");
this.ctx.write(response);
} catch (IOException ioe) {
LOG.debug("Error getting file size", ioe);
this.response = Response.createStringResponse("failure");
this.ctx.write(response);
} finally {
try {
raf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return this.ctx;
}
Response class is responsible for handling various types of response creations (JsonString JsonArray JsonInteger File, etc)
public static FullHttpResponse createFileResponse(long fileLength) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpHeaders.setContentLength(response, fileLength);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "application/octet-stream");
return response;
}
My Api works great for my Json responses(easier to achieve) but It won't work well with my json responses, but not with my file response. When making a request from e.g chrome it only hangs and does not download the file. Should I do something else when downloading a file using netty? I know its not the best wittern code, I still think I have some bits and pieces missing from totally understanding the code, but I would like your advice on how to handle download on my code. For my code I took under consideration this and this
First, some remarks on your code...
Instead of returning ctx, I would prefer to return the last Future for the last command, such that your last event (no keep alive on) could use it directly.
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws IOException {
ChannelFuture future = processMessage(ctx, msg);
if (future != null && !HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
future.addListener(ChannelFutureListener.CLOSE);
}
}
Doing this way will allow to directly close without having any "pseudo" send, even empty.
Important: Note that in Http, the response is managed such that there are chunk send for all data after the first HttpResponse item, until the last one which is empty (LastHttpContent). Sending another empty one (Empty chunk but not LastHttpContent) could break the internal logic.
Moreover, you're doing the work twice (once in read0, once in processMessage), which could lead to some issues perhaps.
Also, since you check for KeepAlive, you should ensure to set it back in the response:
if (HttpHeaders.isKeepAlive(request)) {
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}
On your send, you have 2 choices (depending on the usage of SSL or not): you've selected only the second one, which is more general, so of course valid in all cases but less efficient.
// Write the content.
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture =
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
// Write the end marker.
lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); // <= last writeAndFlush
} else {
sendFileFuture =
ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)),
ctx.newProgressivePromise()); // <= last writeAndFlush
// HttpChunkedInput will write the end marker (LastHttpContent) for us.
lastContentFuture = sendFileFuture;
}
This is this lastContentFuture that you can get back to the caller to check the KeepAlive.
Note however that you didn't include a single flush there (except with your EMPTY_BUFFER but which can be the main reason of your issue there!), contrary to the example (from which I copied the source).
Note that both use a writeAndFlush for the last call (or the unique one).

GWT Catching exception thrown by HttpServlet

From the server Code (in an HttpServlet) I'm throwing an exception if the file is too large:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
...
// Check if the blob has correct size, otherwise delete it
final BlobInfo blobInfo = new BlobInfoFactory().loadBlobInfo(blobKey);
long size = blobInfo.getSize();
if(size > 0 && size <= BasicConstants.maxImageSize){
res.sendRedirect("/download?blob-key=" + blobKey.getKeyString());
} else { // size not allowed
bs.delete(blobKey);
throw new RuntimeException(BasicConstants.fileTooLarge);
}
From the client code I'm missing to successfully catch the exception with this snippet:
try {
uploadForm.submit(); // send file to BlobStore, where the doPost method is executed
} catch (Exception ex) {
GWT.log(ex.toString());
}
However, from this other client code snippet I'm somehow detecting when the exception was thrown with an ugly workaround that I don't trust at all:
uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
// This is what gets the result back - the content-type *must* be
// text-html
String imageUrl =event.getResults();
// This ugly workaround apparently manages to detect when the server threw the exception
if (imageUrl.length() == 0) { // file is too large
uploadFooter.setText(BasicConstants.fileTooLarge);
} else { // file was successfully uploaded
...
}
The Development Mode view in Eclipse reports an error of type "uncaught exception", which suggests that I'm really doing a bad job at detecting it.
Can anyone tell me how to properly catch the exception, and if the workaround I'm using makes any sense?
Thanks!
Your first attempt
try {
uploadForm.submit(); // send file to BlobStore, where the doPost method is executed
} catch (Exception ex) {
GWT.log(ex.toString());
}
doesn't work, because submit() doesn't wait until the browser receives the response (it's an asynchronous call).
uploadForm.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
...
Here you actually receive the response from the server. But it's a form submission, not a GWT-RPC call, so the result is just plain text, not GWT Java Objects.
When you throw a RuntimeException in a Servlet, the server will simply send a response with an error code (probably '500', but ideally use the "Network" tab in Firebug or Chrome Developer Tools to see the actual response and response code.) So in the success case you'll get the URL, otherwise the response is empty.
Possible solution
You can catch Exceptions on the server side, and send better descriptions explicitly:
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
try {
...
if (...) {
throw new MyTooLargeException();
} else {
...
res.getWriter().write("ok " + ...);
}
} catch (MyTooLargeException e) {
res.getWriter().write("upload_size_exceeded"); // just an example string
// (use your own)
res.sendError(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
}
}
Then, on the client, check for
"upload_size_exceeded".equals(event.getResults()).

File Upload with RequestBuilder

I need to upload a file in GWT in the background, ie. not from a visual widget.
For this I've found the RequestBuilder class, but little documentation on how to use it for upload purposes.
The file content I need to upload is 100% plaintext.
My code so far looks like this:
final String filename = UUID.randomUUID().toString() + ".txt";
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, "http://localhost/upload");
rb.setRequestData(selected.getBody()); // getBody() is plain-text
rb.setHeader("Content-Type", "application/x-www-form-urlencodeddata");
rb.setCallback(new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
w.setUrl("http://localhost/magic.html?hide=status&open=" + filename);
w.show();
w.maximize();
}
#Override
public void onError(Request request, Throwable exception) {
exception.printStackTrace();
}
});
// Checked Exceptions sucks *sigh*
try {
rb.send();
}
catch (RequestException e) {
e.printStackTrace();
}
I hope someone can give me some pointers towards solving this issue, thanks!
I think it's not possible to upload files to the server without user interaction using JavaScript only. I think it's blocked by the browser, because it would mean anybody could upload any file from your system when you visit a site, which would be a major security problem. I don't know why you would want to do this, but I guess you need to look at another approach to what you are trying to do.
It seems that you can upload files with gears, so in the worst case you could implement something like this with javascript: link text

Categories

Resources