Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8351109
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 9, 20262026-06-09T08:31:47+00:00 2026-06-09T08:31:47+00:00

Related to Handling HTTP ContentEncoding "deflate" , I’d like to know how to use

  • 0

Related to Handling HTTP ContentEncoding "deflate", I’d like to know how to use an OutputStream to inflate both gzip and deflate streams. Here’s why:

I have a class that fetches resources from a web server (think wget, but in Java). I have it strictly-enforcing the Content-Length of the response and I’d like to keep that enforcement. So, what I’d like to do is read a specific number of bytes from the response (which I’m already doing) but have it generate more bytes if the response has been compressed.

I have this working for deflate responses like this:

OutputStream out = System.out;
out = new InflateOutputStream(out);
// repeatedly:
out.write(compressedBytesFromResponse);

I’d like to be able to do the same thing with gzip responses, but without a GunzipOutputStream, I’m not sure what to do, next.

Update

I was considering building something like this, but it seemed completely insane. Perhaps that is the only way to use an OutputStream to inflate my data.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-09T08:31:48+00:00Added an answer on June 9, 2026 at 8:31 am

    Answering my own question:

    There are two possibilities, here: gunzip on output (e.g. use GunzipOutputStream, not provided by the Java API), or gunzip on input (e.g. use GZIPInputStream, provided by the Java API) plus enforce the Content-Length during the reads.

    I have done both, and I think I prefer the latter because a) it does not require a separate thread to be launched to pump bytes from PipedOutputStream to a PipedIOnputStream and b) (a corollary, I guess) it does not have such a threat of race-conditions and other synchronization issues.

    First, here is my implementation of LimitedInputStream, which allows me to wrap the input stream and enforce a limit on the amount of data read. Note that I also have a BigLimitedInputStream that uses a BigInteger count to support Content-Length values greater than Long.MAX_LONG:

    public class LimitedInputStream
        extends InputStream
    {
        private long _limit;
        private long _read;
        private InputStream _in;
    
        public LimitedInputStream(InputStream in, long limit)
        {
            _limit= limit;
            _in = in;
            _read = 0;
        }
        @Override
        public int available()
            throws IOException
        {
            return _in.available(); // sure?
        }
    
        @Override
        public void close()
            throws IOException
        {
            _in.close();
        }
    
        @Override
        public boolean markSupported()
        {
            return false;
        }
    
        @Override
        public int read()
            throws IOException
        {
            int read = _in.read();
    
            if(-1 == read)
                return -1;
    
            ++_read;
    
            if(_read > _limit)
                return -1;
                // throw new IOException("Read limit reached: " + _limit);
    
            return read;
        }
    
        @Override
        public int read(byte[] b)
            throws IOException
        {
            return read(b, 0, b.length);
        }
    
        @Override
        public int read(byte[] b, int off, int len)
            throws IOException
        {
            // 'len' is an int, so 'max' is an int; narrowing cast is safe
            int max = (int)Math.min((long)(_limit - _read), (long)len);
    
            if(0 == max && len > 0)
                return -1;
                //throw new IOException("Read limit reached: " + _limit);
    
            int read = _in.read(b, off, max);
    
            _read += read;
    
            // This should never happen
            if(_read > _limit)
                return -1;
                //throw new IOException("Read limit reached: " + _limit);
    
            return read;
        }
    
        @Override
        public long skip(long n)
            throws IOException
        {
            long max = Math.min((long)(_limit - _read), n);
    
            if(0 == max)
                return 0;
    
            long read = _in.skip(max);
    
            _read += read;
    
            return read;
        }
    }
    

    Using the above class to wrap the InputStream obtained from the HttpURLConnection allows me to simplify the existing code I had to read the precise number of bytes mentioned in the Content-Length header and just blindly copy input to output. I then wrap the input stream (already wrapped in the LimitedInputStream) in a GZIPInputStream to decompress, and just pump the bytes from (doubly-wrapped) input to output.

    The less-straightforward route is to pursue my original line of though: to wrap the OutputStream using (what turned out to be) an awkward class: GunzipOutputStream. I have written a GunzipOutputStream which uses an internal thread to pump bytes through a pair of piped streams. It’s ugly, and it’s based upon code from OpenRDF’s GunzipOutputStream. I think mine is a bit simpler:

    public class GunzipOutputStream
        extends OutputStream
    {
        final private Thread _pump;
    
        // Streams
        final private PipedOutputStream _zipped;  // Compressed bytes are written here (by clients)
        final private PipedInputStream _pipe; // Compressed bytes are read (internally) here
        final private OutputStream _out; // Uncompressed data is written here (by the pump thread)
    
        // Internal state
        private IOException _e;
    
        public GunzipOutputStream(OutputStream out)
            throws IOException
        {
            _zipped = new PipedOutputStream();
            _pipe = new PipedInputStream(_zipped);
            _out = out;
            _pump = new Thread(new Runnable() {
                public void run() {
                    InputStream in = null;
                    try
                    {
                        in = new GZIPInputStream(_pipe);
    
                        pump(in, _out);
                    }
                    catch (IOException e)
                    {
                        _e = e;
                        System.err.println(e);
                        _e.printStackTrace();
                    }
                    finally
                    {
                        try { in.close(); } catch (IOException ioe)
                        { ioe.printStackTrace(); }
                    }
                }
    
                private void pump(InputStream in, OutputStream out)
                    throws IOException
                {
                    long count = 0;
    
                    byte[] buf = new byte[4096];
    
                    int read;
                    while ((read = in.read(buf)) >= 0) {
                        System.err.println("===> Pumping " + read + " bytes");
                        out.write(buf, 0, read);
                        count += read;
                    }
                    out.flush();
                    System.err.println("===> Pumped a total of " + count + " bytes");
                }
            }, "GunzipOutputStream stream pump " + GunzipOutputStream.this.hashCode());
    
            _pump.start();
        }
    
        public void close() throws IOException {
            throwIOException();
            _zipped.close();
            _pipe.close();
            _out.close();
        }
    
        public void flush() throws IOException {
            throwIOException();
            _zipped.flush();
        }
    
        public void write(int b) throws IOException {
            throwIOException();
            _zipped.write(b);
        }
    
        public void write(byte[] b) throws IOException {
            throwIOException();
            _zipped.write(b);
        }
    
        public void write(byte[] b, int off, int len) throws IOException {
            throwIOException();
            _zipped.write(b, off, len);
        }
    
        public String toString() {
            return _zipped.toString();
        }
    
        protected void finish()
            throws IOException
        {
            try
            {
                _pump.join();
                _pipe.close();
                _zipped.close();
            }
            catch (InterruptedException ie)
            {
                // Ignore
            }
        }
    
        private void throwIOException()
            throws IOException
        {
            if(null != _e)
            {
                IOException e = _e;
                _e = null; // Clear the existing error
                throw e;
            }
        }
    }
    

    Again, this works, but it seems fairly … fragile.

    In the end, I re-factored my code to use the LimitedInputStream and GZIPInputStream and didn’t use the GunzipOutputStream. If the Java API provided a GunzipOutputStream, it would have been great. But it doesn’t, and without writing a “native” gunzip algorithm, implementing your own GunzipOutputStream stretches the limits of propriety.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I feel like every time I need to use TextField or anything else related
While searching SO for approaches to error handling related to business rule validation, all
My question is related to exception handling. If i have for example three methods
Question related to PHP memory-handling from someone not yet very experienced in PHP: If
Related: see here I've got this command: exec((wget -O http://domain/file.zip && mysql -u user
Related to an earlier question I asked, I've seen that there's both LoadComponent() and
Related: How can I use polymorphism in XML Serialization? I have a class I
I'm writing a shell program that must handle signals. My relevant signal handling related
I am implementing a Windows-based web server handling multiple specific HTTP requests from clients
Related to my previous question: Preventing Memory issues when handling large amounts of text

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.