TIdHTTPのGetでエラー

解決


がびょう  URL  2006-01-10 20:56:15  No: 19531  IP: 192.*.*.*

はじめまして、がびょうといいます。

Indy10のTIdHTTPについてですが、

HTTP:=TIdHTTP.Create(nil);
HTTP.Get('http://yahoo.co.jp/');

とやると、
'日付に変換できない値が渡されました'
とエラーが出ます。

http://www.yahoo.co.jp/
でも同じエラーが出ます。Yahoo!以外ならエラーは出ません。
同じようなエラーが出たことがある方はどのようにして解決したかをお教えいただきたいです。
よろしくおねがいします。

編集 削除
原因は…  2006-01-10 21:52:59  No: 19532  IP: 192.*.*.*

Indy9では、そんなエラーは出ないけど、
Yahooのページのヘッダーに
Expires:-1
が含まれているのが原因かな…

編集 削除
葉グリッド  2006-01-10 22:23:29  No: 19533  IP: 192.*.*.*

よくわかんねーけど
IEで保存してからコード見ると<!--京-->ってかいてある部分、自分でデコードするときアソコが引っかかってエラーがおこんだ。
何であんな文字を入れる理由があんだ?
こえー世の中だな。

編集 削除
美乳テーブル  2006-01-10 22:41:43  No: 19534  IP: 192.*.*.*

>何であんな文字を入れる理由があんだ?
ソースがEUCコードで書かれているページには、文字化けを防止するために
<!-- 美乳 -->
をソースコードに入れておくことがよく行われるようで、
<!--京-->
にも同様の効果があるんでしょうね。
さすがにYAHOOは「美乳」を使うのは差し控えたのでは。

編集 削除
がびょう  URL  2006-01-11 19:58:38  No: 19535  IP: 192.*.*.*

そうなんですか...美乳ですか。
解決方法はないんですか?

編集 削除
がびょう  URL  2006-01-11 20:04:33  No: 19536  IP: 192.*.*.*

というか、try〜exceptで無視してもいいんでしょうか?

編集 削除
八&熊  2006-01-12 13:30:25  No: 19537  IP: 192.*.*.*

ハチ: 「日付の変換エラー出るンは、Yahooがアカンの?」
クマ: 「そや、ヘッダーの Expiresフィールド値が-1になってるのが原因やで」
ハチ: 「Indy、ヘボちゃうン?」
クマ: 「-1は'想定外'ちゅうことや」
ハチ: 「ん?そいや、去年'想定内'が流行語やったな〜」
クマ: 「Indy10、空の時刻値には対応したんやけど、-1はアカン」
ハチ: 「ンなら、どないしたらエエん?」
クマ: 「IdGlobalProtocols.pasの GMTToLocalDateTime関数、こう書き換えてや」

//if s = '' then                  // 空文字の場合には対応してる 
  if (s = '')or(s = '-1') then    // '-1'の場合にも対応させる
  begin
    result := 0;
  end
  else
  begin
    Result := RawStrInternetToDateTime(S);
    .....

ハチ: 「ドコやったかいな〜'Expires: 0'ちゅうンもあるで。コレどや?」
クマ: 「うっ、それも'想定外'」

編集 削除
がびょう  URL  2006-01-12 20:21:27  No: 19538  IP: 192.*.*.*

IdGlobalProtocols.pasを修正して、Indyを再コンパイル&再インストールしたんですが、直りません。

編集 削除
DEBUG  2006-01-13 10:32:33  No: 19539  IP: 192.*.*.*

ブレークポイントを設定してTRACEしてみたら?

編集 削除
がびょう  URL  2006-01-15 13:45:12  No: 19540  IP: 192.*.*.*

GMTToLocalDateTimeの
  if s = '' then
の前に
  MessageBox(0,PChar(s),'',0);
をつけてコンパイルしてみたんですが、ダイアログが出ません。
ということは、コンパイルできてない?それか関数が呼ばれていないんだと思うんですが。

編集 削除
DEBUG  2006-01-15 14:04:19  No: 19541  IP: 192.*.*.*

IdGlobalProtocols.pas
IdCompilerDefines.inc
などを自分のプロジェクトのフォルダに入れてコンパイルすること。

編集 削除
がびょう  URL  2006-01-17 19:58:47  No: 19542  IP: 192.*.*.*

やってみました。が、結果は同じです。
コンパイルは出来ているみたいです。

編集 削除
何が同じ?  2006-01-17 21:19:45  No: 19543  IP: 192.*.*.*

ブレークポイントは設定してみたの?

編集 削除
がびょう  URL  2006-01-19 19:27:28  No: 19544  IP: 192.*.*.*

設定してます

編集 削除
簡潔な回答ありがとう  2006-01-19 20:46:08  No: 19545  IP: 192.*.*.*

自分のプロジェクトにコピーしたGIdGlobalProtocols.pasのGMTToLocalDateTime関数にブレークポイントを設定して IdHTTPのGetを実行すれば、ブレークポイントで停止するはず。そのブレークポイントは有効になってる?
そのフォルダ内にGIdGlobalProtocols.dcuファイルは出来てる?

編集 削除
がびょう  URL  2006-01-20 20:15:16  No: 19546  IP: 192.*.*.*

*.dcuはあります。
あと、ブレークポイントを設定して実行するとうまく出来ますが、はずして実行すると例外が発生します。

編集 削除
最長不倒記録は出るか…  2006-01-20 21:18:46  No: 19547  IP: 192.*.*.*

IdGlobalProtocols.pasの GMTToLocalDateTime関数の最初の行、

  if s = '' then                  // 空文字だけに対応

ここにプレークポイント設定すると、IdHttp.Get('http://yahoo.co.jp/')の実行で3回停止する。

1回目の sの値は、'Fri,20 Jan 2006 **:**:** GMT'
2回目の sの値は、空文字
3回目の sの値は、'-1'

3回目で EConvertError例外(日付の変換エラー)が発生するので、その行を

  if (s = '')or(s = '-1') then    // '-1'の場合にも対応

に書き換えて実行すれば、その例外は出なくなる。

※ それでも EIdConnClosedGracefully 'Connection Closed Gracefully'が出るのは、Indyの「お約束」。

編集 削除
がびょう  URL  2006-01-20 22:49:43  No: 19548  IP: 192.*.*.*

-1と0の対策はしました。
たぶんそのお約束の例外です。でてるのは。

編集 削除
がびょう  URL  2006-01-22 16:43:58  No: 19549  IP: 192.*.*.*

解決...かと思ったんですが、Yahoo!カテゴリのどれかをクリックすると
EIdHTTPProtocolException
が発生します。

編集 削除
めざせ!最長不倒記録  2006-01-22 20:17:37  No: 19550  IP: 192.*.*.*

IdHttp.pasの ProcessResponse関数内にブレークポイントを設定してみたら?

編集 削除
篠田雅夫  2006-01-23 12:56:49  No: 19551  IP: 192.*.*.*

久しぶりの投稿です。本題とは外れますが、HTTPのクライアントざっと作ってみました。一応<!-- 美乳 -->や<!--京-->問題を避けられるデコード関数もつけました。
どうしてもIndyがいいというなら虫してください。


unit HTTPClient;

interface
uses
  Classes, Sockets, SysUtils;
type
  TMyHTTP = class(TCustomIpClient)
    property Active;
    property BlockMode;
    property Connected;
    property RemoteHost;
    property RemotePort;
    property OnCreateHandle;
    property OnDestroyHandle;
    property OnConnect;
    property OnDisconnect;
    property OnReceive;
    property OnSend;
    property OnError;
  protected
    FHeader: string;
    function SetHeaderAnswerBody(re: string): string;
  public
    property  Header: string read FHeader;
    constructor Create(AOwner: TComponent); override;
    //function  Head(url: string): string;
    function  Get(url: string): string;
    //function  Post(url: string; dat: string): string;
  end;

procedure        AnalyzeURL(const url: string; var domain: string; var path: string; var param: string; var port: string);
var
  g_LastURL : string = '';
  g_LastDomain: string = '';
  g_LastPath: string = '';
  g_LastParam: string = '';
  g_LastPort: string = '';

function euc2sjis(euc: string): string;

implementation
function euc2sjis(euc: string): string;
var
  i, len: integer;
  w: word;
  h, eucHi, k, l, m, eucLow, eucw: word;

begin
  result := '';
  len := Length(euc);
  if len = 0 then exit;
  i := 1;
  while i <= len do begin
    h := byte(euc[i]);
    case h of
      $A1..$FE: begin
//--------------------
        l := byte(euc[i + 1]);
        eucw := h shl 8 + l;
        case h of
          $F9..$FF: begin
            case eucw of
              $F9A0..$F9C3: w := eucw + $BB;
              $F9C4..$F9FF: w := eucw + $BC;
              $FAA0..$FAE2: w := eucw + $1A;
              $FAE3..$FAFE: w := eucw + $5D;
              $FAFF..$FBA0: w := eucw + $4E;
              $FBA1..$FBFF: w := eucw - $45;
              $FCA1..$FCE2: w := eucw - $E6;
              $FCF1..$FCFA: w := eucw - $2B1;
              $FCE3..$FCEE: w := eucw - $A3;
              $FCFC..$FCFF: w := eucw - $2A7;
              else begin
                w := $8145;
              end;
            end;
            result := result + char(w shr 8) + char(w and $FF);
          end;
          else begin
            case h of
              0..$DE: begin
                k := h - $A1;//3F
                eucHi := $81 + k shr 1;
              end;
              else begin
                k := h - $DF;
                eucHi := $E0 + k shr 1;
              end;
            end;
            l := (eucw and $FF) - $A0;
            m := l shr 4;
            case k mod 2 of
              0: begin
                case m of
                  0: eucLow := $3F + l and $F;
                  1: eucLow := $4F + l and $F;
                  2: eucLow := $5F + l and $F;
                  3: eucLow := $6F + l and $F;
                  4: eucLow := $80 + l and $F;
                  5: eucLow := $90 + l and $F;
                end;
              end;
              1: begin
                case m of
                  0: eucLow := $9E + l and $F;
                  1: eucLow := $AE + l and $F;
                  2: eucLow := $BE + l and $F;
                  3: eucLow := $CE + l and $F;
                  4: eucLow := $DE + l and $F;
                  5: eucLow := $EE + l and $F;
                end;
              end;
            end;
            result := result + char(eucHi) + char(eucLow);
          end;
        end;
//--------------------
        inc(i, 2);
      end;
      else begin
        case h of
          $8E: begin
            if (i + 1) <= len then begin
              result := result + euc[i + 1];
            end;
            inc(i, 2);
          end;
          else begin
            result := result + char(h);
            inc(i);
          end;
        end;


      end;
    end;
  end;
end;

function  TMyHTTP.SetHeaderAnswerBody(re: string): string;
var
  idx: integer;
begin
  idx := pos(#$D#$A + #$D#$A, re);
  FHeader := Copy(re, 1, idx - 1);
  result := Copy(re, idx + 2, Length(re));
end;

procedure        AnalyzeURL(const url: string; var domain: string; var path: string; var param: string; var port: string);
var
        aurl: string;
  idx, idx2: integer;
  s, t: string;
begin
  idx := pos('://', url);
  case idx of
    2..7: begin
      s := trim(Copy(url, 1, idx - 1));
      if s = 'http' then begin
        port := '80';
      end
      else begin
        if s = 'https' then begin
          port := '443';
        end;
      end;
    end;
  end;

        idx := pos(s+'://', url);
        case idx of
      0: begin
            aurl := trim(url);
    end;
         1: begin
            aurl := trim(Copy(url, idx + Length(s) + 3, Length(url)))
    end;
    else begin
      aurl := trim(url);
    end;
  end;

  idx := pos('?', aurl);
  case idx of
           0: begin
            param := '';
    end;
    else begin
            param := Copy(aurl, idx + 1, Length(aurl));
      aurl := Copy(aurl, 1, idx - 1);
    end;
  end;

  idx := pos('/', aurl);
  case idx of
      0: begin
            domain := aurl;
      path := '/';
    end;
    else begin
       domain := Copy(aurl, 1, idx - 1);
      path := Copy(aurl, idx, Length(aurl));
    end;
  end;
  idx := pos(':', domain);
  case idx of
    0:;
    else begin
      domain := Copy(domain, 1, idx - 1);
    end;
  end;
  s := Copy(domain, 1, 1);

  if (s = '') or (s = '.') then begin
    s := StringReplace(g_LastPath, '/', '\', [rfReplaceAll]);
    t := ExtractFileName(s);
    t := Copy(s, 1, Length(s) - Length(t));
    path := StringReplace(t, '\', '/', [rfReplaceAll]) + domain + path;
    domain := g_LastDomain;
  end;

  g_LastURL := url;
  g_LastDomain := domain;
  g_LastPath := path;
  g_LastParam := param;
  g_LastPort := port;
end;

constructor TMyHTTP.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  RemotePort := '80';
  BlockMode := bmBlocking;//bmNonBlocking;
end;
function  TMyHTTP.Get(url: string): string;
var
  domain, path, param: string;
  rq, re: string;
  buf: array[0..1023] of char;
  len: integer;
  port: string;
begin

  AnalyzeURL(url, domain, path, param, port);
  if pos(domain + ':8080', url) > 0 then port := '8080';
  RemoteHost := domain;
  RemotePort := port;
  if param <> '' then begin
    rq := 'GET ' + path + '?' + param + ' HTTP/1.0' + #$D#$A + #$D#$A;
  end
  else begin
    rq := 'GET ' + path + ' HTTP/1.0' + #$D#$A + #$D#$A;
  end;
  re := '';
  Active := true;
  try
    SendBuf(rq[1], Length(rq));
    len := ReceiveBuf(buf, 1024);
    while len > 0 do begin
      re := re + Copy(buf, 1, len);
      len := ReceiveBuf(buf, 1024);
    end;

  finally
     Active := false;
  end;
  re := euc2sjis(re);
  result := SetHeaderAnswerBody(re);
end;

end.

編集 削除
がびょう  URL  2006-01-23 20:37:02  No: 19552  IP: 192.*.*.*

>IdHttp.pasの ProcessResponse関数内にブレークポイントを設定してみたら?

ブレークポイントを設定しても、ブレークポイントの位置にたどり着く前にお約束の例外が出てしまいます。

>HTTPClient
Sockets.dcuが見つかりません...

編集 削除
もしかして、Personal?  2006-01-23 21:27:56  No: 19553  IP: 192.*.*.*

>>HTTPClient
>Sockets.dcuが見つかりません...

Socketsユニットは、D6 Personal版には無いですね。

編集 削除
ハテナ  2006-01-23 23:09:05  No: 19554  IP: 192.*.*.*

>ブレークポイントを設定しても、ブレークポイントの位置にたどり着く前にお約束の例外が出てしまいます。

ブレークポイントが有効になっていれば、そんなことはないけど。
コピーしたIdHttp.pasはコンパイルされている?

編集 削除
がびょう  URL  2006-01-24 20:00:06  No: 19555  IP: 192.*.*.*

>ブレークポイントが有効になっていれば、そんなことはないけど。
>コピーしたIdHttp.pasはコンパイルされている?

コンパイルされてます。

>もしかして、Personal?
D6 Personalです。

編集 削除
それならば…  2006-01-24 21:57:33  No: 19556  IP: 192.*.*.*

ブレークポイントを設定しなかったら、どこで止まる?

編集 削除
がびょう  URL  2006-01-25 20:19:36  No: 19557  IP: 192.*.*.*

えーと、IdIOHandler.pasのTIdIOHandler.RaiseConnClosedGracefullyで、例外は`Connection Closed Gracefully`です。

Yahoo!にアクセスしただけで例外が出ます。

編集 削除
んんん?  2006-01-25 21:35:39  No: 19558  IP: 192.*.*.*

ということは、
EIdHTTPProtocolException例外は出ないの?
>解決...かと思ったんですが、Yahoo!カテゴリのどれかをクリックすると
>EIdHTTPProtocolException
>が発生します。
この問題はどうなったのかな?

編集 削除
がびょう  URL  2006-01-26 19:49:31  No: 19559  IP: 192.*.*.*

デバッグ時には`Connection Closed Gracefully`が出るのでEIdTHHTPProtocolExceptionは出ません。

デバッグ時以外は`Connection Closed Gracefully`がでないのでEIdHTTPProtocolExceptionがでます。

編集 削除
おっ、30  2006-01-26 23:12:23  No: 19560  IP: 192.*.*.*

おかしいな、どのURLを指定してるんだろ?
どのカテゴリ(例えば'http://yahoo.co.jp/r/cet')を選んでも、
EIdTHHTPProtocolException例外が出るけど…

編集 削除
がびょう  URL  2006-01-27 19:45:58  No: 19561  IP: 192.*.*.*

http://yahoo.co.jp/です。

http://yahoo.co.jp/r/cetだと`HTTP/1.0 302 Found`です。
EIdTHHTPProtocolException例外。

編集 削除
にしの  2006-01-27 20:15:56  No: 19562  IP: 192.*.*.*

ステータスコード=302ならば、Locationヘッダに書かれているURLにリダイレクトすべきです。
EIdHTTPProtocolExceptionの説明には、「HTTP応答から予期しないHTTP数値応答コードを受け取った場合に生成される」とかかれていますが、RFCには302が定義されているので予期しないのはおかしいですね。

302などのステータスコードに関しては、RFC2068あたりを参照してください。

編集 削除
にしの  2006-01-27 20:17:41  No: 19563  IP: 192.*.*.*

追記。おかしいのはIdHTTPの実装です。
「実行環境によって異なるのはおかしい」という意味ではないです。IdHTTP自体が、302を考慮していないのでしょう。

編集 削除
がびょう  URL  2006-01-27 20:28:38  No: 19564  IP: 192.*.*.*

解決策はないんでしょうか?

編集 削除
祝、30突破  2006-01-27 20:49:47  No: 19565  IP: 192.*.*.*

でるふぁい: 「自分、Redirectに対応したンいつやったかいな?」
いんでぃ10: 「2000年の初夏やったな〜、オヤジのいんでぃ9からやろ」
でるふぁい: 「もう4年も過ぎとるで、エエかげんデフォルトで飛ばんかい」
いんでぃ10: 「飛ばんのは、おれンちの主義や」
でるふぁい: 「ンなら、実力行使や。IdHttp.pasの365行目のId_TIdHTTP_HandleRedirects、Trueに書き換えたる」
いんでぃ10: 「そないな荒療治せんで、HandleRedirectsぷろぱてぃ、Trueにしといたらエエやン」
でるふぁい: 「デフォルトで飛ばんオマエの根性、気にくわんのや」
いんでぃ10: 「ナニ言うても、主義は変えへんで」
でるふぁい: 「おいおい、仕様はコロコロ変えとるやんか」
いんでぃ10: 「それも、おれンちの主義や。文句あっか?」

編集 削除
がびょう  URL  2006-01-29 17:47:00  No: 19566  IP: 192.*.*.*

無事解決しました。
協力してくださった方々、本当にありがとうございました。

編集 削除