Google-GData .net Library が buggy?

開発言語は C#

状況
Picasa Web API を叩いて写真をアップロードしようとすると、しばしば例外 GDataRequestException が起こる。再現性が取れず、成功するときもあれば枚数に関わらず発生することもある。
---------------------------
エラー
---------------------------
System.Net.WebException: 基礎になる接続が閉じられました: 接続が予期せずに閉じられました
   場所 System.Net.HttpWebRequest.GetResponse()
   場所 Google.GData.Client.GDataRequest.Execute()
Execution of request failed: http://picasaweb.google.com/data/feed/api/user/*********/albumid/5291********************

原因推測

  • PicasaService.Insert() で画像をuploadしようとする
  • Google.GData.Client.GDataRequest クラスの Execute() メソッドが実行される
  • System.Net.HttpWebRequest クラスを経由して HTTP/1.1 で request が行われる(HttpWebRequest.GetResponse() メソッドが実行される)
  • .net Framework 3.5 では、 HTTP request は Expect: 100-continue ヘッダと共に 1.1 で発行される
  • Google 側のサーバーは HTTP/1.1 に対応している(っぽい。ヘッダを見る限り。)

本来、HTTP/1.1 の仕様上は、 W3C の規格書/RFC にもあるとおり、

The purpose of the 100 (Continue) status (see section 10.1.1) is to allow a client that is sending a request message with a request body to determine if the origin server is willing to accept the request (based on the request headers) before the client sends the request body. In some cases, it might either be inappropriate or highly inefficient for the client to send the body if the server will reject the message without looking at the body.

というように、formデータ(form body)を送信する前に、一度サーバー側に受け入れ体制が整っているかを確認し、OK(=100: continue)が返れば実データの送信を開始する、という仕組みになっています。これはformで送信されるデータは比較的大きいことが多く、仮にサーバー側での受け入れ体制が整わないままに送信してしまうと、全ての作業が無駄になってしまうため、そのコストを抑えることが目的のようです。

ところが、ライブラリSDKではその辺は特に考慮してないみたいで、確認を取る前にいきなりデータを送信してしまいます。しかし、.net F/W、サーバーともに 100 ヘッダを前提として動いているにもかかわらず、ライブラリがいきなり実データを送信してしまうため、その不整合が原因となってエラーを引き起こしている模様。だいたいの場合はサーバー側で上手く処理してくれるようで 201 Created ヘッダが返ってくるわけだけど、時折サーバー側が送られたデータを無視して 100 Continue を返してくることもあって、本来ならクライアント側はその時にデータを POST しなきゃならないんだけど、そこに対応する処理コードが存在しないっぽい。

これを回避するためにはユーザー側での対処*1が必要で、とりあえずの対処としては、

System.Net.ServicePointManager.FindServicePoint(ALBUMURI).Expect100Continue = false;

で Expect: 100-continue を殺せるとのこと。ALBUMURI は適宜 request 先の URI に変更してくだしあ。