Servlet-API und setContentLength()

20.10.2015

In meiner Laufbahn als Softwareentwickler trifft man manche Stellen immer und immer wieder. So ist es mir die Tage mit der Servlet-API ergangen. Bei der Suche nach einem Bug bin ich auf folgende Stelle in einem Download-Servlet gestoßen:

response.setContentLength((int) file.getSize());

Hier wird ein „cast“ vom Datentyp „long“ zu einem „int“ durchgeführt. Das ist an sich eigentlich kein Problem solange die Dateigröße nicht den Wert Integer.MAX_INT (2147483647) übersteigt. Das bedeutet einfach ausgedrückt, dass Dateien mit einer maximalen Größe von 2 GB übertragen werden können.

Aber was passiert mit Dateien die größer sind? Um das zu veranschaulichen habe ich einen kleinen Test implementiert:

public class Test {
    public static void main(String[] args) {
        System.out.println("IntegerMaxValueCalculated:" + (int) ((1024 * 1024 * 1024 * 2) -1));
        System.out.println("IntegerMaxValuePlusOne   :" + (int) ((1024 * 1024 * 1024 * 2) +1));
        System.out.println("IntegerMaxValueToHight   :" + (int) ((1024 * 1024 * 1024 * 4)));
        System.out.println("IntegerMaxValueToHight   :" + (int) ((1024 * 1024 * 1024 * 4) + 1));
    }
}

Die Ausgabe sieht wie folgt aus:

IntegerMaxValueCalculated:2147483647
IntegerMaxValuePlusOne   :-2147483647
IntegerMaxValueToHight   :0
IntegerMaxValueToHight   :1

Es tritt also kein Fehler auf, sondern ein Überlauf. Dieser führt dazu, dass falsche Werte an den Browser übermittelt werden und die Dateigrößen verfälscht wird.

Beheben kann man das Problem in dem man die Methdode „setContentLength“ nicht verwendet und stattdessen den Header manuell setzt.

response.addHeader("Content-Length", Long.toString(file.getSize())); 

Daraufhin habe ich mir die aktuelle Servlet-API angeschaut und habe nicht schlecht gestaunt. Die Macher der Servlet-API haben es inzwischen geschafft mit der Version 3.1 (enthalten ab Java EE7) folgende Methode zu definieren:

/**
 * Sets the length of the content body in the response
 * In HTTP servlets, this method sets the HTTP Content-Length header.
 *
 * @param len a long specifying the length of the 
 * content being returned to the client; sets the Content-Length header
 *
 * @since Servlet 3.1
 */
public void setContentLengthLong(long len);

Somit ist in Zukunft an dieser Stelle kein Workaround mehr nötig.

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*