@Override
  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime();
    while (true) {
      HttpResponse httpResponse = null;
      byte[] responseContents = null;
      Map<String, String> responseHeaders = new HashMap<String, String>();
      try {
        // Gather headers.
        Map<String, String> headers = new HashMap<String, String>();
        addCacheHeaders(headers, request.getCacheEntry());
        httpResponse = mHttpStack.performRequest(request, headers);
        StatusLine statusLine = httpResponse.getStatusLine();
        int statusCode = statusLine.getStatusCode();

        responseHeaders = convertHeaders(httpResponse.getAllHeaders());
        // Handle cache validation.
        if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
          return new NetworkResponse(
              HttpStatus.SC_NOT_MODIFIED,
              request.getCacheEntry() == null ? null : request.getCacheEntry().data,
              responseHeaders,
              true);
        }

        // Some responses such as 204s do not have content.  We must check.
        if (httpResponse.getEntity() != null) {
          responseContents = entityToBytes(httpResponse.getEntity());
        } else {
          // Add 0 byte response as a way of honestly representing a
          // no-content request.
          responseContents = new byte[0];
        }

        // if the request is slow, log it.
        long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
        logSlowRequests(requestLifetime, request, responseContents, statusLine);

        if (statusCode < 200 || statusCode > 299) {
          throw new IOException();
        }
        return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
      } catch (SocketTimeoutException e) {
        attemptRetryOnException("socket", request, new TimeoutError());
      } catch (ConnectTimeoutException e) {
        attemptRetryOnException("connection", request, new TimeoutError());
      } catch (MalformedURLException e) {
        throw new RuntimeException("Bad URL " + request.getUrl(), e);
      } catch (IOException e) {
        int statusCode = 0;
        NetworkResponse networkResponse = null;
        if (httpResponse != null) {
          statusCode = httpResponse.getStatusLine().getStatusCode();
        } else {
          throw new NoConnectionError(e);
        }
        VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
        if (responseContents != null) {
          networkResponse =
              new NetworkResponse(statusCode, responseContents, responseHeaders, false);
          if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {
            attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
          } else {
            // TODO: Only throw ServerError for 5xx status codes.
            throw new ServerError(networkResponse);
          }
        } else {
          throw new NetworkError(networkResponse);
        }
      }
    }
  }
  @Override
  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime();
    while (true) {
      HttpResponse httpResponse = null;
      byte[] responseContents = null;
      Map<String, String> responseHeaders = new HashMap<String, String>();
      try {
        // Log Params
        logParams(request);
        // Gather headers.
        Map<String, String> headers = new HashMap<String, String>();

        headers.put("Accept-Encoding", "gzip");
        headers.put("Connection", "Keep-Alive");

        addCacheHeaders(headers, request.getCacheEntry());
        httpResponse = mHttpStack.performRequest(request, headers);

        StatusLine statusLine = httpResponse.getStatusLine();
        int statusCode = statusLine.getStatusCode();

        responseHeaders = convertHeaders(httpResponse.getAllHeaders());
        // Handle cache validation.
        if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
          return new NetworkResponse(
              HttpStatus.SC_NOT_MODIFIED, request.getCacheEntry().data, responseHeaders, true);
        }

        //                responseContents = entityToBytes(httpResponse.getEntity());
        responseContents = entityToBytes(httpResponse);
        // if the request is slow, log it.
        long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
        logSlowRequests(requestLifetime, request, responseContents, statusLine);

        if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_NO_CONTENT) {
          throw new IOException();
        }
        return new NetworkResponse(statusCode, responseContents, responseHeaders, false);
      } catch (SocketTimeoutException e) {
        //            	e.printStackTrace();
        if (!request.allowRetry()) return null;
        attemptRetryOnException("socket", request, new TimeoutError());
      } catch (ConnectTimeoutException e) {
        //            	e.printStackTrace();
        if (!request.allowRetry()) return null;
        attemptRetryOnException("connection", request, new TimeoutError());
      } catch (MalformedURLException e) {
        //            	e.printStackTrace();
        throw new RuntimeException("Bad URL " + request.getUrl(), e);
      } catch (IOException e) {
        //            	e.printStackTrace();
        if (!request.allowRetry()) return null;
        int statusCode = 0;
        NetworkResponse networkResponse = null;
        if (httpResponse != null) {
          statusCode = httpResponse.getStatusLine().getStatusCode();
        } else {
          throw new NoConnectionError(e);
        }
        VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
        if (responseContents != null) {
          networkResponse =
              new NetworkResponse(statusCode, responseContents, responseHeaders, false);
          if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {
            attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
          } else {
            // TODO: Only throw ServerError for 5xx status codes.
            throw new ServerError(networkResponse);
          }
        } else {
          throw new NetworkError(networkResponse);
        }
      }
    }
  }
  @Override
  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime();
    while (true) {
      HttpResponse httpResponse = null;
      byte[] responseContents = null;
      Map<String, String> responseHeaders = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
      try {
        // Gather headers.
        Map<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
        addCacheHeaders(headers, request.getCacheEntry());
        httpResponse = mHttpStack.performRequest(request, headers);
        responseHeaders.putAll(httpResponse.getAllHeaders());
        int statusCode = httpResponse.getResponseCode();

        // Handle cache validation.
        if (statusCode == HttpResponse.SC_NOT_MODIFIED) {

          Entry entry = request.getCacheEntry();
          if (entry == null) {
            return new NetworkResponse(
                HttpResponse.SC_NOT_MODIFIED,
                null,
                responseHeaders,
                true,
                SystemClock.elapsedRealtime() - requestStart);
          }

          // A HTTP 304 response does not have all header fields. We
          // have to use the header fields from the cache entry plus
          // the new ones from the response.
          // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
          entry.responseHeaders.putAll(responseHeaders);
          return new NetworkResponse(
              HttpResponse.SC_NOT_MODIFIED,
              entry.data,
              entry.responseHeaders,
              true,
              SystemClock.elapsedRealtime() - requestStart);
        }

        // Handle moved resources
        if (statusCode == HttpResponse.SC_MOVED_PERMANENTLY
            || statusCode == HttpResponse.SC_MOVED_TEMPORARILY) {
          String newUrl = responseHeaders.get("Location");
          request.setRedirectUrl(newUrl);
        }

        // Some responses such as 204s do not have content.  We must check.
        if (httpResponse.getEntity() != null) {
          responseContents = entityToBytes(httpResponse.getEntity());
        } else {
          // Add 0 byte response as a way of honestly representing a
          // no-content request.
          responseContents = new byte[0];
        }

        // if the request is slow, log it.
        long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
        logSlowRequests(requestLifetime, request, responseContents, httpResponse);

        if (statusCode < 200 || statusCode > 299) {
          throw new IOException();
        }
        return new NetworkResponse(
            statusCode,
            responseContents,
            responseHeaders,
            false,
            SystemClock.elapsedRealtime() - requestStart);
      } catch (SocketTimeoutException e) {
        attemptRetryOnException("socket", request, new TimeoutError());
      } catch (ConnectTimeoutException e) {
        attemptRetryOnException("connection", request, new TimeoutError());
      } catch (MalformedURLException e) {
        throw new RuntimeException("Bad URL " + request.getUrl(), e);
      } catch (IOException e) {
        int statusCode = 0;
        NetworkResponse networkResponse = null;
        if (httpResponse != null) {
          statusCode = httpResponse.getResponseCode();
        } else {
          throw new NoConnectionError(e);
        }
        if (statusCode == HttpResponse.SC_MOVED_PERMANENTLY
            || statusCode == HttpResponse.SC_MOVED_TEMPORARILY) {
          VolleyLog.e(
              "Request at %s has been redirected to %s", request.getOriginUrl(), request.getUrl());
        } else {
          VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
        }
        if (responseContents != null) {
          networkResponse =
              new NetworkResponse(
                  statusCode,
                  responseContents,
                  responseHeaders,
                  false,
                  SystemClock.elapsedRealtime() - requestStart);
          if (statusCode == HttpResponse.SC_UNAUTHORIZED
              || statusCode == HttpResponse.SC_FORBIDDEN) {
            attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
          } else if (statusCode == HttpResponse.SC_MOVED_PERMANENTLY
              || statusCode == HttpResponse.SC_MOVED_TEMPORARILY) {
            attemptRetryOnException("redirect", request, new RedirectError(networkResponse));
          } else {
            // TODO: Only throw ServerError for 5xx status codes.
            throw new ServerError(networkResponse);
          }
        } else {
          throw new NetworkError(e);
        }
      }
    }
  }