简体   繁体   中英

Using GZIPOutputStream to send a compressed chunk in java

I'm trying to send a compressed HTML file through a java socket but the browser displays an empty HTML file.

The thing is, when I try to send the uncompressed HTML everything works find (yes I do modify the HTTP headers accordingly).

private void sendResponse(String headers, String body) throws IOException
{   
    BufferedOutputStream output = new BufferedOutputStream(
        this.SOCKET.getOutputStream());
    byte[] byteBody = null;

    // GZIP compression
    if(body != null && this.encoding.contains("gzip"))
    {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
        zipStream.write(body.getBytes(this.charset));
        zipStream.flush();
        byteBody = byteStream.toByteArray();
        byteStream.flush();
        byteStream.close();
        zipStream.close();
    }
    else
        byteBody = body.getBytes(this.charset);

    // Sending response
    byte[] msg1 = (Integer.toHexString(byteBody.length) + "\r\n")
        .getBytes(this.charset);
    byte[] msg2 = byteBody;
    byte[] msg3 = ("\r\n" + "0").getBytes(this.charset);

    output.write(headers.getBytes(this.charset));
    output.write(msg1);
    output.write(msg2);
    output.write(msg3);
    output.flush();
    output.close();
}

Basically, headers contains the HTTP headers, and body the HTML file. The rest seems self explanatory. What could cause such a behavior?

EDIT: The header is generated as such:

    headers = "HTTP/1.1 200 OK\r\n";
    headers += "Date: " + WebServer.getServerTime(Calendar.getInstance()) + "\r\n";
    headers += "Content-Type: text/html; charset=" + this.charset + "\r\n";
    headers += "Set-Cookie: sessionID=" + newCookie + "; Max-Age=600\r\n";
    headers += "Connection: close \r\n";
    if(this.encoding.contains("gzip"))
        headers += "Content-Encoding: gzip\r\n";
    headers += "Transfer-Encoding: chunked \r\n";
    headers += "\r\n";

The problem is that a GZIPOutputStream isn't complete until the finish() method has been called.

It is automatically called when you close() the stream.

Since you are calling byteStream.toByteArray() before that has happened, you're not getting complete data.

Also, you don't need to call flush() since that is also automatically done when you call close() . And closing the GZIPOutputStream automatically closes the underlying stream(s) (ie the ByteArrayOutputStream ).

So, you code should be:

ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
zipStream.write(body.getBytes(this.charset));
zipStream.close();
byteBody = byteStream.toByteArray();

A simple test class should show you where the problem is:

import java.io.ByteArrayOutputStream;
import java.util.zip.GZIPOutputStream;

public class GZipTest {

    public final static void main(String[] args) throws Exception {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gzos = new GZIPOutputStream(baos);

        gzos.write("some data".getBytes());
        System.out.println("baos before gzip flush: " + baos.size());
        gzos.flush();
        System.out.println("baos after gzip flush: " + baos.size());
        gzos.close();
        System.out.println("baos after gzip close: " + baos.size());
    }
}

This leads to the following output:

baos before gzip flush: 10
baos after gzip flush: 10
baos after gzip close: 29

You're closing your GZIPOutputStream after building you body data, so the browser receives incomplete GZIP-data and therefor can't decompress it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM