Content disposition duplicate headers solution for google chrome

Recently I had a problem while serving dynamic content in a Spring MVC application; (more details here) when attempting to open some of the dynamic content with Chrome I was having a weird error message :

Duplicate headers received from server The response from the server contained duplicate headers. This problem is generally the result of a misconfigured website or proxy. Only the website or proxy administrator can fix this issue. Error 349 (net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION): Multiple distinct Content-Disposition headers received. This is disallowed to protect against HTTP response splitting attacks.

I wasn't sure why I was having this problem, since some dynamic content was working properly and I was setting only once the Content-Disposition header on my code

So after searching around a bit I stumbled upon the HTTP specs it turns out the Content-Disposition header should not contain a coma since it will be treated as a header separator

Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma.

Personally I decided to create slugs for all my file names using the Slugify library :



    com.github.slugify
    slugify
    2.1.3


  public String slugify(String originalFileName){

      String extension = FilenameUtils.getExtension(originalFileName);
      return new Slugify(true).slugify(FilenameUtils.removeExtension(originalFileName)) +"."+extension;;

  }

Spring mvc send binary content from controller

Sometimes binary files such as images, documents are stored in the database; these binary files need then to be served dynamically

Below I'll show a code snippet showing how to handle this easily with Spring MVC

Before we begin just in case this is the list of libraries I used when coding this example :

  • Spring 3+
  • Spring Data JPA
  • Eclipselink 2.4+
  • Apache Tika
  • Slugify


@Entity
public class Resouce{

    @Id @Column(name = "ID")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "FILE_NAME", length = 200)
    private String fileName;


   @Column(name = "FILE")
    @Lob
    private byte[] file;

   //SETTERS - GETTERS OMMITED
}


@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {

}


/**
 * @author ulf
 */
@Controller
@RequestMapping("/resource")
public class ResourceController{

    // a basic Spring data repository
    @Autowired
    private ResourceRepostiory resourceRepository;

    
    // simple tika instance for handling mimetype resolution
    @Autowired
    private Tika tika;

    @RequestMapping(method = RequestMethod.GET)
    public ResponseEntity resource(@RequestParam("resourceId") Long resourceId) throws IOException {

        byte[] binary = null;
        String fileName = "";


            Resouce resource= resourceRepository.findOne(resourceId);

            if (resource!= null  && section.getFile() !=null ) {
                binary = section.getFile();
                fileName = section.getFileName();
            }


        if (binary == null) {
            throw new ResourceNotFoundException();
        } else {

            String extension = FilenameUtils.getExtension(fileName);

            // slugify the fileName to handle the Google Chrome error complaining of duplicate content disposition headers whenever the file name contains a ,
            fileName = new Slugify(true).slugify(FilenameUtils.removeExtension(fileName)) +"."+extension;

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType(mimetype(fileName)));
            headers.setContentDispositionFormData(fileName, fileName);
            headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
            ResponseEntity responseEntity = new ResponseEntity(binary, headers, HttpStatus.OK);
            return responseEntity;


        }


    }

    private String mimetype(String fileName) {
        return ConfigurableMimeFileTypeMap.getDefaultFileTypeMap().getContentType(fileName);
    }


}


And that's it you should now be able to serve resources dynamically based on their id

Angular6 hiding component selector

It's sometimes useful to have angular's component selector not to be rendered in the page, as sometimes this can cause problems with...