code: public void run() {
          synchronized (this) {
              started = true;
          }
          finished = false;
          finish = false;
  
          try {
              while (true) {
                  waitForInput(is);
  
                  if (finish || Thread.interrupted()) {
                      break;
                  }
  
                  int availableBytes = is.available();
                  byte[] buf = new byte[availableBytes];
                  int actualBytesRead = is.read(buf, 0, availableBytes);
  
                  if (actualBytesRead <= 0 || finish || Thread.interrupted()) {
                      break;
                  }
                  os.write(buf, 0, actualBytesRead);
                  if (autoflush) {
                      os.flush();
                  }
              }
              os.flush();
          } catch (InterruptedException ie) {
              // likely PumpStreamHandler trying to stop us
          } catch (Exception e) {
              synchronized (this) {
                  exception = e;
              }
          } finally {
              if (closeWhenExhausted) {
                  FileUtils.close(os);
              }
              finished = true;
              synchronized (this) {
                  notifyAll();
              }
          }
      }
docs: Copies data from the input stream to the output stream.
  
  Terminates as soon as the input stream is closed or an error occurs.