HttpClientを実装していてIllegal domain attributeのCookie rejectedを回避したい時…

なんだよソレ?どんな時だよw って話はおいといて…。 ブラウザってこんな事してんのかなーってのがちょっと垣間見れたのでメモ的な。   ■ 事象 諸事情で異なるVIPを経由して裏からとあるサービスにアクセスして、 HTTPClientを作ってマッシュアップ的な事をしたい、と。   ■ Cookieドメイン指定 呼び出し先の各サービスはCookieを発行する際はドメインを設定してレスポンスするので、 ↓こんなんが出てしまったりします。この警告嫌なので、、、

警告: Cookie rejected: "$Version=0; hoge=hage; $Path=/; $Domain=.shinodogg.com". Illegal domain attribute ".shinodogg.com". Domain of origin: "shinodogg.intra.com"

  ■ とりあえずCookieを吐くだけのサーブレット作ります。

public void doGet(HttpServletRequest request, HttpServletResponse response)
 throws IOException, ServletException{
 
 Cookie cookie;
 cookie = new Cookie("hoge", "hage");
 cookie.setDomain(".shinodogg.com"); ★ ドメイン指定します
 cookie.setPath("/");
 cookie.setMaxAge(60*5);
 response.addCookie(cookie);
 
 response.setContentType("text/html");
 
 PrintWriter out = response.getWriter();
 out.println("<html>");
 out.println("<head>");
 out.println("<title>Hello World!</title>");
 out.println("</head>");
 out.println("<body>");
 out.println("<h1>Hello World!</h1>");
 out.println("</body>");
 out.println("</html>");
}

  ■ 上記サーブレットを呼び出すHTTPクライアント。(ライブラリは commons-httpclient-3.1.jar )

HttpClient httpClient = new HttpClient();
int status = httpClient.executeMethod(new GetMethod("http://localhost:8080/CookiePolicy/servlet/set"));
System.out.println("status:" + status);

  ■ commons-httpclient-3.1.jarのソースが欲しかったんだけど…orz なんかMavenでイイ感じに取れないので、、、

C:eclipseworkspacehttp_client_test>C:apache-maven-2.2.1binmvn dependency:sources
〜略〜
[INFO] The following files have NOT been resolved:
[INFO]    commons-codec:commons-codec:java-source:sources:1.2
[INFO]    commons-httpclient:commons-httpclient:java-source:sources:3.1

ググったら↓が出てきたのでコレをアタッチする感じで。 http://www.docjar.com/jar_detail/com.springsource.org.apache.commons.httpclient-sources-3.1.0.jar.html   ■ RFC2109Spec()をみると ↓こんな事やってます、と。

if (host.indexOf('.') >= 0) {
 if (!host.endsWith(cookie.getDomain())) {
  throw new MalformedCookieException(
   "Illegal domain attribute "" + cookie.getDomain()
    + "". Domain of origin: "" + host + """);
 }
 // host minus domain may not contain any dots
 String hostWithoutDomain = host.substring(0, host.length()
  - cookie.getDomain().length());
  if (hostWithoutDomain.indexOf('.') != -1) {
   throw new MalformedCookieException("Domain attribute ""
    + cookie.getDomain()
    + "" violates RFC 2109: host minus domain may not contain any dots");
  }
 }
}

  ■ ってことでRFC2109Specを継承して…

public class HogeSpec extends RFC2109Spec{
 public void validate(String host, int port, String   path,
  boolean secure, final Cookie cookie) throws MalformedCookieException {
  System.out.println("HogeSpac is called");
 }
}

  ■ HttpClientにvalidateしないSpecをセット

HttpMethod method = new GetMethod("http://localhost:8080/CookiePolicy/servlet/set");
CookiePolicy.registerCookieSpec(CookiePolicy.DEFAULT, HogeSpec.class);
method.getParams().setCookiePolicy(CookiePolicy.DEFAULT);

動かしてみると、下記のように呼ばれました、と。

Hello World!
HogeSpac is called
status:200

  ■ ところが、 RFC2109Specのvalidateメソッドをパクってきて上記のとこだけ コメントアウトすれば動くのかと思ったのですが、、

// Perform generic validation
super.validate(host, port, path, secure, cookie);
// Perform RFC 2109 specific validation

って事になってて、CookieSpecBaseのvalidateが呼ばれてます、と。 CookieSpecBaseでは以下のようにドメインチェックしてました。

// Validate the cookies domain attribute.  NOTE:  Domains without
// any dots are allowed to support hosts on private LANs that don't
// have DNS names.  Since they have no dots, to domain-match the
// request-host and domain must be identical for the cookie to sent
// back to the origin-server.
if (host.indexOf(".") >= 0) {
 // Not required to have at least two dots.  RFC 2965.
 // A Set-Cookie2 with Domain=ajax.com will be accepted.
 
 // domain must match host
 if (!host.endsWith(cookie.getDomain())) {
  String s = cookie.getDomain();
  if (s.startsWith(".")) {
   s = s.substring(1, s.length());
  }
  if (!host.equals(s)) {
   throw new MalformedCookieException(
    "Illegal domain attribute "" + cookie.getDomain()
    + "". Domain of origin: "" + host + """);
  }
 }
} else {
 if (!host.equals(cookie.getDomain())) {
  throw new MalformedCookieException(
   "Illegal domain attribute "" + cookie.getDomain()
   + "". Domain of origin: "" + host + """);
 }
}

  ■ ということでHogeSpecはCookieSpecBaseを継承することにして、

System.out.println( "Hello World!" );
HttpClient httpClient = new HttpClient();
HttpMethod method = new GetMethod("http://localhost:8080/CookiePolicy/servlet/set");
CookiePolicy.registerCookieSpec(CookiePolicy.DEFAULT, HogeSpec.class);
int status = httpClient.executeMethod(method);
System.out.println("status:" + status);

以下のように狙った結果になったので、まぁメデタシな感じです。

Hello World!
HogeSpac is called
status:200

  特定のホストの時だけ握り潰す、と。 # あんまりこういうことしたくないけど…

public class HogeSpec extends CookieSpecBase {
 public void validate(String host, int port, String path, boolean secure,
   final Cookie cookie) throws MalformedCookieException {
  System.out.println("HogeSpac is called");
 
  LOG.trace("enter CookieSpecBase.validate("
    + "String, port, path, boolean, Cookie)");
  if (host == null) {
   throw new IllegalArgumentException("Host of origin may not be null");
  }
  if (host.trim().equals("")) {
   throw new IllegalArgumentException(
     "Host of origin may not be blank");
  }
  if (port < 0) {
   throw new IllegalArgumentException("Invalid port: " + port);
  }
  if (path == null) {
   throw new IllegalArgumentException(
     "Path of origin may not be null.");
  }
  if (path.trim().equals("")) {
   path = PATH_DELIM;
  }
  host = host.toLowerCase();
  // check version
  if (cookie.getVersion() = 0) {
   // Not required to have at least two dots. RFC 2965.
   // A Set-Cookie2 with Domain=ajax.com will be accepted.
 
   /* domainのワーニングが出ないように */
   if(!host.equals("shinodogg01.intra.com") && !host.equals("shinodogg02.intra.com)) {
   /* 特定のホストはスキップする */
 
    // domain must match host
    if (!host.endsWith(cookie.getDomain())) {
     String s = cookie.getDomain();
     if (s.startsWith(".")) {
      s = s.substring(1, s.length());
     }
     if (!host.equals(s)) {
      throw new MalformedCookieException(
        "Illegal domain attribute "" + cookie.getDomain()
          + "". Domain of origin: "" + host + """);
     }
    }
 
   /* スキップ */
   }
   /* ここまで */
    
  } else {
   /* ローカル開発時にdomainのワーニングが出ないように */
   if (!host.equals("localhost")) {
   /* localhostはスキップする */
 
    if (!host.equals(cookie.getDomain())) {
     throw new MalformedCookieException(
       "Illegal domain attribute "" + cookie.getDomain()
         + "". Domain of origin: "" + host + """);
    }
 
   /* スキップ */
   }
   /* ここまで */
 
  }
 
  // another security check... we musn't allow the server to give us a
  // cookie that doesn't match this path
 
  if (!path.startsWith(cookie.getPath())) {
   throw new MalformedCookieException("Illegal path attribute ""
     + cookie.getPath() + "". Path of origin: "" + path + """);
  }
 }
}