コード例 #1
0
ファイル: RedirectionModule.java プロジェクト: aheritier/ws
  /** Invoked by the HTTPClient. */
  public int responsePhase2Handler(Response resp, Request req) throws IOException {
    /* handle various response status codes until satisfied */

    int sts = resp.getStatusCode();
    switch (sts) {
      case 302: // General (temporary) Redirection (handle like 303)

        /*
         * Note we only do this munging for POST and PUT. For GET it's not
         * necessary; for HEAD we probably want to do another HEAD. For all
         * others (i.e. methods from WebDAV, IPP, etc) it's somewhat unclear -
         * servers supporting those should really return a 307 or 303, but some
         * don't (guess who...), so we just don't touch those.
         */
        if (req.getMethod().equals("POST") || req.getMethod().equals("PUT")) {
          if (LOG.isDebugEnabled())
            LOG.debug(
                "Received status: " + sts + " " + resp.getReasonLine() + " - treating as 303");

          sts = 303;
        }

      case 301: // Moved Permanently
      case 303: // See Other (use GET)
      case 307: // Moved Temporarily (we mean it!)
        if (LOG.isDebugEnabled()) LOG.debug("Handling status: " + sts + " " + resp.getReasonLine());

        // the spec says automatic redirection may only be done if
        // the second request is a HEAD or GET.
        if (!req.getMethod().equals("GET") && !req.getMethod().equals("HEAD") && sts != 303) {
          if (LOG.isDebugEnabled())
            LOG.debug("Not redirected because method is neither HEAD nor GET");

          if (sts == 301 && resp.getHeader("Location") != null)
            update_perm_redir_list(req, resLocHdr(resp.getHeader("Location"), req));

          resp.setEffectiveURI(lastURI);
          return RSP_CONTINUE;
        }

      case 305: // Use Proxy
      case 306: // Switch Proxy
        if (sts == 305 || sts == 306) {
          if (LOG.isDebugEnabled())
            LOG.debug("Handling status: " + sts + " " + resp.getReasonLine());
        }

        // Don't accept 305 from a proxy
        if (sts == 305 && req.getConnection().getProxyHost() != null) {
          if (LOG.isDebugEnabled()) LOG.debug("305 ignored because a proxy is already in use");

          resp.setEffectiveURI(lastURI);
          return RSP_CONTINUE;
        }

        /*
         * the level is a primitive way of preventing infinite redirections.
         * RFC-2068 set the max to 5, but RFC-2616 has loosened this. Since some
         * sites (notably M$) need more levels, this is now set to the
         * (arbitrary) value of 15 (god only knows why they need to do even 5
         * redirections...).
         */
        if (level >= 15 || resp.getHeader("Location") == null) {
          if (LOG.isDebugEnabled()) {
            if (level >= 15) LOG.debug("Not redirected because of too many levels of redirection");
            else LOG.debug("Not redirected because no Location header was present");
          }

          resp.setEffectiveURI(lastURI);
          return RSP_CONTINUE;
        }
        level++;

        URI loc = resLocHdr(resp.getHeader("Location"), req);

        HTTPConnection mvd;
        String nres;
        new_con = false;

        if (sts == 305) {
          mvd =
              new HTTPConnection(
                  req.getConnection().getProtocol(),
                  req.getConnection().getHost(),
                  req.getConnection().getPort());
          mvd.setCurrentProxy(loc.getHost(), loc.getPort());
          mvd.setContext(req.getConnection().getContext());
          new_con = true;

          nres = req.getRequestURI();

          /*
           * There was some discussion about this, and especially Foteos
           * Macrides (Lynx) said a 305 should also imply a change to GET (for
           * security reasons) - see the thread starting at
           * http://www.ics.uci.edu/pub/ietf/http/hypermail/1997q4/0351.html
           * However, this is not in the latest draft, but since I agree with
           * Foteos we do it anyway...
           */
          req.setMethod("GET");
          req.setData(null);
          req.setStream(null);
        } else if (sts == 306) {
          // We'll have to wait for Josh to create a new spec here.
          return RSP_CONTINUE;
        } else {
          if (req.getConnection().isCompatibleWith(loc)) {
            mvd = req.getConnection();
            nres = loc.getPathAndQuery();
          } else {
            try {
              mvd = new HTTPConnection(loc);
              nres = loc.getPathAndQuery();
            } catch (ProtocolNotSuppException e) {
              if (req.getConnection().getProxyHost() == null
                  || !loc.getScheme().equalsIgnoreCase("ftp")) return RSP_CONTINUE;

              // We're using a proxy and the protocol is ftp -
              // maybe the proxy will also proxy ftp...
              mvd =
                  new HTTPConnection(
                      "http",
                      req.getConnection().getProxyHost(),
                      req.getConnection().getProxyPort());
              mvd.setCurrentProxy(null, 0);
              nres = loc.toExternalForm();
            }

            mvd.setContext(req.getConnection().getContext());
            new_con = true;
          }

          /*
           * copy query if present in old url but not in new url. This isn't
           * strictly conforming, but some scripts fail to propagate the query
           * properly to the Location header. See comment on line 126. String
           * oquery = Util.getQuery(req.getRequestURI()), nquery =
           * Util.getQuery(nres); if (nquery == null && oquery != null) nres +=
           * "?" + oquery;
           */

          if (sts == 303) {
            // 303 means "use GET"

            if (!req.getMethod().equals("HEAD")) req.setMethod("GET");
            req.setData(null);
            req.setStream(null);
          } else {
            // If they used an output stream then they'll have
            // to do the resend themselves
            if (req.getStream() != null) {
              if (!HTTPConnection.deferStreamed) {
                if (LOG.isDebugEnabled())
                  LOG.debug("Status " + sts + " not handled - request has an output stream");

                return RSP_CONTINUE;
              }

              saved_req = (Request) req.clone();
              deferred_redir_list.put(req.getStream(), this);
              req.getStream().reset();
              resp.setRetryRequest(true);
            }

            if (sts == 301) {
              // update permanent redirection list
              try {
                update_perm_redir_list(req, new URI(loc, nres));
              } catch (ParseException pe) {
                throw new Error(
                    "HTTPClient Internal Error: " + "unexpected exception '" + pe + "'", pe);
              }
            }
          }

          // Adjust Referer, if present
          NVPair[] hdrs = req.getHeaders();
          for (int idx = 0; idx < hdrs.length; idx++)
            if (hdrs[idx].getName().equalsIgnoreCase("Referer")) {
              HTTPConnection con = req.getConnection();
              hdrs[idx] = new NVPair("Referer", con + req.getRequestURI());
              break;
            }
        }

        req.setConnection(mvd);
        req.setRequestURI(nres);

        try {
          resp.getInputStream().close();
        } catch (IOException ioe) {
          if (LOG.isTraceEnabled()) {
            LOG.trace("An exception occurred: " + ioe.getMessage());
          }
        }

        if (sts != 305 && sts != 306) {
          try {
            lastURI = new URI(loc, nres);
          } catch (ParseException pe) {
            if (LOG.isTraceEnabled()) {
              LOG.trace("An exception occurred: " + pe.getMessage());
            }
          }

          if (LOG.isDebugEnabled())
            LOG.debug(
                "Request redirected to "
                    + lastURI.toExternalForm()
                    + " using method "
                    + req.getMethod());
        } else {
          if (LOG.isDebugEnabled())
            LOG.debug(
                "Resending request using "
                    + "proxy "
                    + mvd.getProxyHost()
                    + ":"
                    + mvd.getProxyPort());
        }

        if (req.getStream() != null) return RSP_CONTINUE;
        else if (new_con) return RSP_NEWCON_REQ;
        else return RSP_REQUEST;

      default:
        return RSP_CONTINUE;
    }
  }