docs: public void executeMethod(final HttpMethod method) throws IOException, HttpException {
          if (method == null) {
              throw new IllegalArgumentException("Method may not be null");
          }
          // Link all parameter collections to form the hierarchy:
          // Global -> HttpClient -> HostConfiguration -> HttpMethod
          this.hostConfiguration.getParams().setDefaults(this.params);
          method.getParams().setDefaults(this.hostConfiguration.getParams());
          
          // Generate default request headers
          Collection<?> defaults = (Collection<?>)this.hostConfiguration.getParams().
  			getParameter(HostParams.DEFAULT_HEADERS);
          if (defaults != null) {
          	Iterator<?> i = defaults.iterator();
          	while (i.hasNext()) {
          		method.addRequestHeader((Header)i.next());
          	}
          }
          
          try {
              int maxRedirects = this.params.getIntParameter(HttpClientParams.MAX_REDIRECTS, 100);
  
              for (int redirectCount = 0;;) {
  
                  // make sure the connection we have is appropriate
                  if (this.conn != null && !hostConfiguration.hostEquals(this.conn)) {
                      this.conn.setLocked(false);
                      this.conn.releaseConnection();
                      this.conn = null;
                  }
          
                  // get a connection, if we need one
                  if (this.conn == null) {
                      this.conn = connectionManager.getConnectionWithTimeout(
                          hostConfiguration,
                          this.params.getConnectionManagerTimeout() 
                      );
                      this.conn.setLocked(true);
                      if (this.params.isAuthenticationPreemptive()
                       || this.state.isAuthenticationPreemptive()) 
                      {
                          LOG.debug("Preemptively sending default basic credentials");
                          method.getHostAuthState().setPreemptive();
                          method.getHostAuthState().setAuthAttempted(true);
                          if (this.conn.isProxied() && !this.conn.isSecure()) {
                              method.getProxyAuthState().setPreemptive();
                              method.getProxyAuthState().setAuthAttempted(true);
                          }
                      }
                  }
                  authenticate(method);
                  executeWithRetry(method);
                  if (this.connectMethod != null) {
                      fakeResponse(method);
                      break;
                  }
                  
                  boolean retry = false;
                  if (isRedirectNeeded(method)) {
                      if (processRedirectResponse(method)) {
                          retry = true;
                          ++redirectCount;
                          if (redirectCount >= maxRedirects) {
                              LOG.error("Narrowly avoided an infinite loop in execute");
                              throw new RedirectException("Maximum redirects ("
                                  + maxRedirects + ") exceeded");
                          }
                          if (LOG.isDebugEnabled()) {
                              LOG.debug("Execute redirect " + redirectCount + " of " + maxRedirects);
                          }
                      }
                  }
                  if (isAuthenticationNeeded(method)) {
                      if (processAuthenticationResponse(method)) {
                          LOG.debug("Retry authentication");
                          retry = true;
                      }
                  }
                  if (!retry) {
                      break;
                  }
                  // retry - close previous stream.  Caution - this causes
                  // responseBodyConsumed to be called, which may also close the
                  // connection.
                  if (method.getResponseBodyAsStream() != null) {
                      method.getResponseBodyAsStream().close();
                  }
  
              } //end of retry loop
          } finally {
              if (this.conn != null) {
                  this.conn.setLocked(false);
              }
              // If the response has been fully processed, return the connection
              // to the pool.  Use this flag, rather than other tests (like
              // responseStream == null), as subclasses, might reset the stream,
              // for example, reading the entire response into a file and then
              // setting the file as the stream.
              if (
                  (releaseConnection || method.getResponseBodyAsStream() == null) 
                  && this.conn != null
              ) {
                  this.conn.releaseConnection();
              }
          }
  
      }