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 + """);
  }
 }
}

 
 

Jakarta Commonsクックブック ―Javaプロジェクト必須のレシピ集
Timothy M. O’Brien
オライリージャパン
売り上げランキング: 281927

コメント

タイトルとURLをコピーしました