'gRPC file upload detect content type of file on server

I am trying to do a file upload on via client streaming gRPC. Sending a file via streaming from client to server.

I have implemented this code for server side which receives the files. I would like the server to only accept the files of a specific type lets say image files of the format .png ,.bmp,.jpeg and many more may be.

So the client shouldn't be able to upload any other type of file other than the ones listed above.

How do I achieve this in gRPC ?

For the file upload sample I have referred this link

Server side code to process the request,

public class FileUploadService extends FileServiceGrpc.FileServiceImplBase {

    private static final Path SERVER_BASE_PATH = Paths.get("src/test/resources/output");

    @Override
    public StreamObserver<FileUploadRequest> upload(StreamObserver<FileUploadResponse> responseObserver) {
        return new StreamObserver<FileUploadRequest>() {
            // upload context variables
            OutputStream writer;
            Status status = Status.IN_PROGRESS;

            @Override
            public void onNext(FileUploadRequest fileUploadRequest) {
                try{
                    if(fileUploadRequest.hasMetadata()){
                        writer = getFilePath(fileUploadRequest);
                    }else{
                        writeFile(writer, fileUploadRequest.getFile().getContent());
                    }
                }catch (IOException e){
                    this.onError(e);
                }
            }

            @Override
            public void onError(Throwable throwable) {
                status = Status.FAILED;
                this.onCompleted();
            }

            @Override
            public void onCompleted() {
                closeFile(writer);
                status = Status.IN_PROGRESS.equals(status) ? Status.SUCCESS : status;
                FileUploadResponse response = FileUploadResponse.newBuilder()
                        .setStatus(status)
                        .build();
                responseObserver.onNext(response);
                responseObserver.onCompleted();
            }
        };
    }

    private OutputStream getFilePath(FileUploadRequest request) throws IOException {
        var fileName = request.getMetadata().getName() + "." + request.getMetadata().getType();
        return Files.newOutputStream(SERVER_BASE_PATH.resolve(fileName), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }

    private void writeFile(OutputStream writer, ByteString content) throws IOException {
        writer.write(content.toByteArray());
        writer.flush();
    }

    private void closeFile(OutputStream writer){
        try {
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Proto file

package file;

option java_package = "com.vinsguru.io";
option java_multiple_files = true;

message MetaData {
  string name = 1;
  string type = 2;
}

message File {
  bytes content = 1;
}

enum Status {
  PENDING = 0;
  IN_PROGRESS = 1;
  SUCCESS = 2;
  FAILED = 3;
}

message FileUploadRequest {
  oneof request {
    MetaData metadata = 1;
    File file = 2;
  }
}

message FileUploadResponse {
  string name = 1;
  Status status = 2;
}

service FileService {
  rpc upload(stream FileUploadRequest) returns(FileUploadResponse);
}


Solution 1:[1]

Assuming you don't want to just trust the file extension of the file, you will need to probe the file contents to determine its type. If you trust your client, you could consider just using FileTypeDetector.

If you don't trust your client, then your server must inspect the incoming file data and cancel the transfer if it detects an unsupported file type. To do this you could look at incorporating e.g. Apache Tika to your server.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Terry