2009-06-25 16 views
2

私はDelphiでnsIProtocolHandlerを実装しています。 (more here) これはすでに動作しています。モジュールビルドのデータは、nsIInputStreamを介してストリーミングされます。私はすべてのnsIRequest、nsIChannel、およびnsIHttpChannelのメソッドとプロパティを持っています。nsIProtocolHandler:htmlページの画像の読み込みに問題があります

私はテストを始めました。私は奇妙なことに遭遇しました。 Firefoxで作業

<img src="a.png">

どちらも "xxm::://test/a.html" と "//test/a.png xxm" 私はこの単純なHTMLでページ "a.html" を持っています上記のHTMLまたはPNG画像データを渡すことができます。 問題はHTMLページを表示することで、画像が読み込まれないことです。私はデバッグするとき、私は以下を参照してください(Firefoxはa.htmlにOnDataAvailable通知を処理しているとき)

  • NewChannelが
  • NotificationCallbacksが設定されている、a.pngのために呼び出されます(私は唯一の参照を保持する必要があり、右?)
  • RequestHeader「Accept」が「image/png,image/*;q=0.8,*/*;q=0.5
  • 設定されているが、その後、チャネルオブジェクトが他のrequを見てみると

)最もおそらくゼロ参照カウントに(解放されます私はいくつかの他のプロパティ(LoadFlagsやOriginalURIなど)を取得し、AsyncOpenが呼び出されて、どこから要求が返ってくるかを知ることができます。

誰でもこれを認識できますか?私は何か間違っているのですか?おそらくLoadFlagsやLoadGroupで?私は、LoadGroupのAddRequestとRemoveRequestを呼び出すタイミングがわからないので、nsHttpChannelnsBaseChannelから覗いています。OnStartRequestまたはOnStopRequestの前または後にRemoveRequestを早くまたは遅く呼び出す方が良いとは思いませんか?

アップデート:<img src="xxm://test/a.png" />と:「//test/a1.htmlファイルを」さらに問題を特定しようとするために、私は試してみてください。は、まだ同じ

更新したばかりの新しいFirefox 3.5の上でチェック起こっているイベントのシーケンスの上にしか到達しません。 私は、ロードグループにAsyncOpenを呼び出すために、このsecundaryリクエストを追加することになっていますが、どこへの参照を取得するかはわかりません。

詳細:リクエストヘッダに追加される「受け入れる」文字列のone instanceが見つかりました。新しいチャネルを作成した直後にnsIHttpChannelInternalを照会しましたが、このQueryInterfaceコールは取得されません。 (私はそれを投稿here

答えて

0

this pageをよく見てください。なぜUUIDがバージョン上で変更されたのか分かりませんが、それは明らかではありませんが、nsIHttpChannelInternal上でQueryInterfaceを呼び出すとき(またはその直前)に何が失敗するのかを説明します。

新しい(er)UUIDでは、より良い結果が得られます。私が質問の更新で述べたように、私はbugzilla.mozilla.orgにこれを掲載しました。

0

私はもう一度。

私はnsIChannel::asyncOpen()から同じものを引用するつもりです:

asyncOpenもし戻っは成功し、 チャネルは、それがaListeneronStopRequestと呼ばれたり onChannelRedirectと呼ばれるまで生き自体 を維持する責任があります。

あなたが戻っnsViewSourceChannel.cppに行けば、loadGroup->RemoveRequestが呼び出されているloadGroup->AddRequestが呼び出された一箇所と2つの場所があります。

nsViewSourceChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt) 
{ 
    NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE); 

    mListener = aListener; 

    /* 
    * We want to add ourselves to the loadgroup before opening 
    * mChannel, since we want to make sure we're in the loadgroup 
    * when mChannel finishes and fires OnStopRequest() 
    */ 

    nsCOMPtr<nsILoadGroup> loadGroup; 
    mChannel->GetLoadGroup(getter_AddRefs(loadGroup)); 
    if (loadGroup) 
     loadGroup->AddRequest(NS_STATIC_CAST(nsIViewSourceChannel*, 
              this), nsnull); 

    nsresult rv = mChannel->AsyncOpen(this, ctxt); 

    if (NS_FAILED(rv) && loadGroup) 
     loadGroup->RemoveRequest(NS_STATIC_CAST(nsIViewSourceChannel*, 
               this), 
           nsnull, rv); 

    if (NS_SUCCEEDED(rv)) { 
     mOpened = PR_TRUE; 
    } 

    return rv; 
} 

nsViewSourceChannel::OnStopRequest(nsIRequest *aRequest, nsISupports* aContext, 
           nsresult aStatus) 
{ 
    NS_ENSURE_TRUE(mListener, NS_ERROR_FAILURE); 
    if (mChannel) 
    { 
     nsCOMPtr<nsILoadGroup> loadGroup; 
     mChannel->GetLoadGroup(getter_AddRefs(loadGroup)); 
     if (loadGroup) 
     { 
      loadGroup->RemoveRequest(NS_STATIC_CAST(nsIViewSourceChannel*, 
                this), 
            nsnull, aStatus); 
     } 
    } 
    return mListener->OnStopRequest(NS_STATIC_CAST(nsIViewSourceChannel*, 
                this), 
            aContext, aStatus); 
} 

編集

私はMozillaがどのように機能するかについての手掛かりを持っていないので、私はいくつかのコードを読んでから推測する必要があります。チャネルの視点から、元のファイルがロードされると、そのジョブが完了します。イメージのようにリンクされたセカンダリ項目をロードする場合は、それをリスナに実装する必要があります。 TestPageLoad.cppを参照してください。これは、原油のパーサーを実装し、それがOnDataAvailable時に子項目を取得します。

NS_IMETHODIMP 
MyListener::OnDataAvailable(nsIRequest *req, nsISupports *ctxt, 
          nsIInputStream *stream, 
          PRUint32 offset, PRUint32 count) 
{ 
    //printf(">>> OnDataAvailable [count=%u]\n", count); 
    nsresult rv = NS_ERROR_FAILURE; 
    PRUint32 bytesRead=0; 
    char buf[1024]; 

    if(ctxt == nsnull) { 
     bytesRead=0; 
     rv = stream->ReadSegments(streamParse, &offset, count, &bytesRead); 
    } else { 
     while (count) { 
     PRUint32 amount = PR_MIN(count, sizeof(buf)); 
     rv = stream->Read(buf, amount, &bytesRead); 
     count -= bytesRead; 
     } 
    } 

    if (NS_FAILED(rv)) { 
     printf(">>> stream->Read failed with rv=%x\n", rv); 
     return rv; 
    } 

    return NS_OK; 
} 

重要なことは、それがimgsrc属性とscript要素を見ている、streamParse()を呼び出し、auxLoad()を呼び出して、新しいと新しいチャネルを作成することですリスナーに電話し、AsyncOpen()に電話してください。また、ロシアの人形のような状況のように無限に多くの子項目を読み込むことができ

uriList->AppendElement(uri); 
rv = NS_NewChannel(getter_AddRefs(chan), uri, nsnull, nsnull, callbacks); 
RETURN_IF_FAILED(rv, "NS_NewChannel"); 

gKeepRunning++; 
rv = chan->AsyncOpen(listener, myBool); 
RETURN_IF_FAILED(rv, "AsyncOpen"); 

それはそこにMyListenerオブジェクトの別のインスタンスを渡していますので、。

+0

これは非常に混乱しています。私は非常に匹敵する場所で私のAddRequest/RemoveRequest呼び出しを持っていますが、どちらもSetLoadGroupまたはAsyncOpenがPNGのチャンネルで呼び出されることはありません。 ViewSourceChannelはnsIStreamListener.OnStartRequest呼び出しで設定される "mChannel"を使用しますが、nsIStreamListenerを自分のチャンネルに追加すると、そのメソッドは呼び出されません。 –

+0

質問についてはsecond updateを参照してください。 –

+0

@Stijn Sanders、私は答えを更新しました。 –