public long determineLength(HttpMessage httpMessage) throws HttpException {
   Args.notNull(httpMessage, "HTTP message");
   Header firstHeader = httpMessage.getFirstHeader(HTTP.TRANSFER_ENCODING);
   if (firstHeader != null) {
     String value = firstHeader.getValue();
     if (HTTP.CHUNK_CODING.equalsIgnoreCase(value)) {
       if (!httpMessage.getProtocolVersion().lessEquals(HttpVersion.HTTP_1_0)) {
         return -2;
       }
       throw new ProtocolException(
           "Chunked transfer encoding not allowed for " + httpMessage.getProtocolVersion());
     } else if (HTTP.IDENTITY_CODING.equalsIgnoreCase(value)) {
       return -1;
     } else {
       throw new ProtocolException("Unsupported transfer encoding: " + value);
     }
   }
   firstHeader = httpMessage.getFirstHeader(HTTP.CONTENT_LEN);
   if (firstHeader == null) {
     return (long) this.implicitLen;
   }
   String value2 = firstHeader.getValue();
   try {
     long parseLong = Long.parseLong(value2);
     if (parseLong >= 0) {
       return parseLong;
     }
     throw new ProtocolException("Negative content length: " + value2);
   } catch (NumberFormatException e) {
     throw new ProtocolException("Invalid content length: " + value2);
   }
 }
    /**
     * Implements a patch out in 4.1.x and 4.2 that isn't available in 4.0.x which fixes a bug where
     * connections aren't reused when the response is gzipped. See
     * https://issues.apache.org/jira/browse/HTTPCORE-257 for info about the issue, and
     * http://svn.apache.org/viewvc?view=revision&revision=1124215 for the patch which is copied
     * here.
     */
    @Override
    public boolean keepAlive(final HttpResponse response, final HttpContext context) {
      if (response == null) {
        throw new IllegalArgumentException("HTTP response may not be null.");
      }
      if (context == null) {
        throw new IllegalArgumentException("HTTP context may not be null.");
      }

      // Check for a self-terminating entity. If the end of the entity
      // will
      // be indicated by closing the connection, there is no keep-alive.
      ProtocolVersion ver = response.getStatusLine().getProtocolVersion();
      Header teh = response.getFirstHeader(HTTP.TRANSFER_ENCODING);
      if (teh != null) {
        if (!HTTP.CHUNK_CODING.equalsIgnoreCase(teh.getValue())) {
          return false;
        }
      } else {
        Header[] clhs = response.getHeaders(HTTP.CONTENT_LEN);
        // Do not reuse if not properly content-length delimited
        if (clhs == null || clhs.length != 1) {
          return false;
        }
        Header clh = clhs[0];
        try {
          int contentLen = Integer.parseInt(clh.getValue());
          if (contentLen < 0) {
            return false;
          }
        } catch (NumberFormatException ex) {
          return false;
        }
      }

      // Check for the "Connection" header. If that is absent, check for
      // the "Proxy-Connection" header. The latter is an unspecified and
      // broken but unfortunately common extension of HTTP.
      HeaderIterator hit = response.headerIterator(HTTP.CONN_DIRECTIVE);
      if (!hit.hasNext()) hit = response.headerIterator("Proxy-Connection");

      // Experimental usage of the "Connection" header in HTTP/1.0 is
      // documented in RFC 2068, section 19.7.1. A token "keep-alive" is
      // used to indicate that the connection should be persistent.
      // Note that the final specification of HTTP/1.1 in RFC 2616 does
      // not
      // include this information. Neither is the "Connection" header
      // mentioned in RFC 1945, which informally describes HTTP/1.0.
      //
      // RFC 2616 specifies "close" as the only connection token with a
      // specific meaning: it disables persistent connections.
      //
      // The "Proxy-Connection" header is not formally specified anywhere,
      // but is commonly used to carry one token, "close" or "keep-alive".
      // The "Connection" header, on the other hand, is defined as a
      // sequence of tokens, where each token is a header name, and the
      // token "close" has the above-mentioned additional meaning.
      //
      // To get through this mess, we treat the "Proxy-Connection" header
      // in exactly the same way as the "Connection" header, but only if
      // the latter is missing. We scan the sequence of tokens for both
      // "close" and "keep-alive". As "close" is specified by RFC 2068,
      // it takes precedence and indicates a non-persistent connection.
      // If there is no "close" but a "keep-alive", we take the hint.

      if (hit.hasNext()) {
        try {
          TokenIterator ti = createTokenIterator(hit);
          boolean keepalive = false;
          while (ti.hasNext()) {
            final String token = ti.nextToken();
            if (HTTP.CONN_CLOSE.equalsIgnoreCase(token)) {
              return false;
            } else if (HTTP.CONN_KEEP_ALIVE.equalsIgnoreCase(token)) {
              // continue the loop, there may be a "close"
              // afterwards
              keepalive = true;
            }
          }
          if (keepalive) return true;
          // neither "close" nor "keep-alive", use default policy

        } catch (ParseException px) {
          // invalid connection header means no persistent connection
          // we don't have logging in HttpCore, so the exception is
          // lost
          return false;
        }
      }

      // default since HTTP/1.1 is persistent, before it was
      // non-persistent
      return !ver.lessEquals(HttpVersion.HTTP_1_0);
    }