Constructing a DataSource from an InputStream or Byte array

35,400

Solution 1

This was rather simple actually, I just copied over the bytes from the InputStream to the DataSource:

FileItem f = files.get(0);

// there is a problem here where the file being created is empty, since we only have a
// partial path:
DataSource source = new FileDataSource(new File(f.getName()));

// because of the above problem, we are going to copy over the data ourselves:
byte[] sourceBytes = f.get();
OutputStream sourceOS = source.getOutputStream();
sourceOS.write(sourceBytes);

Solution 2

  • This is the code of commons-email ByteArrayDataSource
  • it sounds odd to try to replace apache commons - don't, unless you have a really good reason
  • you can get absolute paths in a servlet. You can call getServletContext().getRealPath("/") which will return the absolute path of your application, and then you can get files relative to it.

Solution 3

In our application there are objects that have properties InputStream and Name. We are using next class to construct DataSource with those properties.

public class InputStreamDataSource implements DataSource {

    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    private final String name;

    public InputStreamDataSource(InputStream inputStream, String name) {
        this.name = name;
        try {
            int nRead;
            byte[] data = new byte[16384];
            while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
              buffer.write(data, 0, nRead);
            }
            inputStream.close();
            buffer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public String getContentType() {            
        return new MimetypesFileTypeMap().getContentType(name);
    }

    @Override
    public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(buffer.toByteArray());
    }

    @Override
    public String getName() {
       return name;
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        throw new IOException("Read-only data");
    }

}
Share:
35,400
Casey
Author by

Casey

Long time developer and hacker currently working as a security consultant in the Application Security field. My focus is on attacking web applications and code audits. I also do mobile application assessments and develop a lot of training around offensive web hacking techniques.

Updated on February 12, 2020

Comments

  • Casey
    Casey about 4 years

    I am writing a small file upload utility thing as part of a larger project. Originally I was handling this from a servlet using the Apache commons File utility classes. Here is a snippet from a quick test client I wrote for the service:

    public static void main(String[] args) {
    
      JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
    
     factory.getInInterceptors().add(new LoggingInInterceptor());
     factory.getOutInterceptors().add(new LoggingOutInterceptor());
     factory.setServiceClass(FileUploadService.class);
     factory.setAddress("http://localhost:8080/FileUploadService/FileUploadService");
     FileUploadService client = (FileUploadService) factory.create();
    
     FileType file = new FileType();
     file.setName("statemo_1256144312279");
     file.setType("xls");
    
     DataSource source = new FileDataSource(new File("c:/development/statemo_1256144312279.xls"));
     file.setHandler(new DataHandler(source));
     Boolean ret = client.uploadFile(file);
     System.out.println (ret);
     System.exit(0);
    

    }

    This works absolutely fine. Now the problem comes when I am trying to replace the Apache commons utilities. In the above code I am creating a DataSource from a File with an absolute path name. In my servlet, I can't get an absolute path name however and the file I am sending over the wire is empty.

    Here is the servlet code:

     @SuppressWarnings("unchecked")
        protected void doPost (final HttpServletRequest request, final HttpServletResponse response) 
            throws ServletException, IOException {
    
        // form should have enctype="multipart/form-data" as an attribute
     if (!ServletFileUpload.isMultipartContent (request)) {
      LOG.info("Invalid form attribute");
      return;
     }
    
     //DataInputStream in = new DataInputStream(request.getInputStream());
    
     final DiskFileItemFactory factory = new DiskFileItemFactory ();
     factory.setSizeThreshold(FILE_THRESHOLD_SIZE);
    
     final ServletFileUpload sfu = new ServletFileUpload (factory);
     sfu.setSizeMax(MAX_FILE_SIZE);
    
     final HttpSession session = request.getSession();
    
     final List<FileItem> files = new ArrayList<FileItem>();
    
     final List<String> filesToProcess = new ArrayList<String>();
    
     try {
            final List<FileItem> items = sfu.parseRequest(request);
    
            for (final FileItem f : items) {
                if (!f.isFormField())
                    files.add(f);
            }
    
            /*for (final FileItem f : files) {
             final String absoluteFileName = UPLOAD_DESTINATION + FilenameUtils.getName(f.getName());
    
                //f.write(new File (absoluteFileName));
                filesToProcess.add(absoluteFileName);
            }*/
    
            FileItem f = files.get(0);
    
            LOG.info("File: " + FilenameUtils.getName(f.getName()));
            LOG.info("FileBaseName: " + FilenameUtils.getBaseName(f.getName()));
            LOG.info("FileExtension: " + FilenameUtils.getExtension(f.getName()));
    
            FileUploadServiceClient client = new FileUploadServiceClient();
    
            DataSource source = new FileDataSource(new File(f.getName()));
    
            FileType file = new FileType();
            file.setHandler(new DataHandler(source));
            file.setName(FilenameUtils.getBaseName(f.getName()));
            file.setType(FilenameUtils.getExtension(f.getName()));
    
            Boolean ret = client.uploadFile(file);
    
            LOG.info("File uploaded - " + ret);
    
            filesToProcess.add(UPLOAD_DESTINATION + FilenameUtils.getName(f.getName()));
            session.setAttribute("filesToProcess", filesToProcess);
    
      final RequestDispatcher dispatcher = request.getRequestDispatcher("Validate");
            if (null != dispatcher) {
             dispatcher.forward(request, response);
            }
        } catch (FileUploadException e) {
            LOG.info("Exception " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            LOG.info("Exception " + e.getMessage());
            e.printStackTrace();
        }
    

    }

    I've been working on this for the better part of this morning and am not getting anywhere. Even if I get rid of the Apache commons file stuff completely and handle the parsing of the request myself, I still can't construct the DataSource appropriately.

    Thanks!