新しいPythonだときっと直ってるんでしょうけれど……
はてなボトルの質問を Quitteer/Quetter/Q&Aなう に流してみる - 風柳メモでも少し触れましたが、Google App Engine の開発に Python 2.5.4 を使っていて、これの CookieJar()が、Set-Cookieのパースに失敗して誤動作する(どうも、カンマ(", ")区切りで複数のCookieが入っていると対応できない)という現象に出会って往生しました。
新バージョンを探して入れたりするのが面倒だったこともあり*1、強引にパッチを当てて対応しましたので、メモ書き。
class patchedCookieJar(CookieJar): def __init__(self, *args, **kwargs): self.re_is_setcookie = re.compile(u'^set-cookie2?$',re.I) self.re_header_name = re.compile(u'^(.*?):\s*') self.re_cookie_sep = re.compile(u'([^a-z]),\s*') CookieJar.__init__(self, *args, **kwargs) def make_cookies(self,response,request): msg = response.info() msg.org_getallmatchingheaders = msg.getallmatchingheaders def _getallmatchingheaders(name): if not self.re_is_setcookie.search(name): return msg.org_getallmatchingheaders(name) s_list = msg.org_getallmatchingheaders(name) t_list = [] for _val in s_list: _val = self.re_header_name.sub(r'',_val) t_list += [name+': ' +_v for _v in self.re_cookie_sep.sub(r'\1\n',_val).split('\n') if _v] return t_list msg.getallmatchingheaders = _getallmatchingheaders response.info = lambda: msg return CookieJar.make_cookies(self,response,request)
CookieJar()のサブクラスを作って、make_cookie()を上書きし、getallmatchingheaders() の処理を無理やり書換えているだけです。
これで、例えば
policy = DefaultCookiePolicy(rfc2965=True,netscape=True) cjar = CookieJar(policy=policy) cjar_handler = urllib2.HTTPCookieProcessor(cjar) url_opener = urllib2.build_opener(cjar_handler)
のようなコードなら、CookieJarをpatchedCookieJarに置換して、
policy = DefaultCookiePolicy(rfc2965=True,netscape=True) cjar = patchedCookieJar(policy=policy) # ← cjar = CookieJar(policy=policy) cjar_handler = urllib2.HTTPCookieProcessor(cjar) url_opener = urllib2.build_opener(cjar_handler)
のようにすれば、とりあえずカンマ区切りのSet-Cookieを受信した場合でも、きちんと複数のCookieが保存されるようになりました。
とりあえずこれで凌いでますが、正式な対応方法をご存じの方は教えて下さい。
*1:もしかしたら、本番環境ではちゃんと動いたりしてね…