2

Delphi で nsIProtocolHandler 実装を構築しています。(詳細はこちら) そして、それはすでに機能しています。モジュールが構築するデータは、nsIInputStream を介してストリーミングされます。nsIRequest、nsIChannel、および nsIHttpChannel のすべてのメソッドとプロパティが機能しています。

テストを開始しましたが、奇妙なことに遭遇しました。この単純な HTML を含むページ "a.html" があります。

<img src="a.png">

"xxm://test/a.html" と "xxm://test/a.png" はどちらも Firefox で動作し、上記の HTML または PNG 画像データを提供します。問題は HTML ページの表示にあり、画像が読み込まれません。デバッグすると、次のように表示されます。

  • a.png に対して NewChannel が呼び出されます (Firefox が a.html で OnDataAvailable 通知を処理している場合)。
  • NotificationCallbacks が設定されています (参照を保持するだけで十分ですよね?)
  • RequestHeader " " は " "Acceptに設定されていますimage/png,image/*;q=0.8,*/*;q=0.5
  • ただし、その後、チャネル オブジェクトが解放されます (ほとんどの場合、参照カウントがゼロのため)。

他のリクエストを見ると、他のいくつかのプロパティ (LoadFlags や OriginalURI など) が設定され、AsyncOpenが呼び出されることが予想されます。ここから、リクエストへの応答を開始できます。

誰もこれを認識していますか?私は何か間違ったことをしていますか?おそらく、LoadFlags または LoadGroup でしょうか? LoadGroup で AddRequest と RemoveRequest を呼び出すタイミングがわかりません。また、nsHttpChannelnsBaseChannelからのぞきます

更新:新しくなった Firefox 3.5 で確認しましたが、同じです。

更新:問題をさらに特定するために、「file://test/a1.html」を試してみましたが<img src="xxm://test/a.png" />、発生しているイベントのシーケンスを超えるだけです。この2 次リクエストを負荷グループに追加して、AsyncOpen を呼び出すことになっている場合、その参照をどこで取得すればよいかわかりません。

さらに:リクエスト ヘッダーに追加された "Accept" 文字列のインスタンスを 1 つだけ見つけました。新しいチャネルを作成した直後に nsIHttpChannelInternal をクエリしますが、この QueryInterface 呼び出しを取得することさえできません... (私は投稿しましたここにある)

4

2 に答える 2

0

私はそれを(自分で)見つけたと思います。このページをよく見てください。UUID がバージョンごとに変更されたことが強調されていない理由は明確ではありませんが、nsIHttpChannelInternal で QueryInterface を呼び出すとき (またはその直前) に失敗する理由を説明できます。

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

于 2009-07-03T11:57:06.673 に答える
0

私は再び。

から同じものを引用しますnsIChannel::asyncOpen()

正常に返された場合、チャネルは、 onまたは asyncOpenが呼び出されるまで自身を存続させる責任があります 。onStopRequestaListeneronChannelRedirect

nsViewSourceChannel.cppに戻ると、 が呼び出される場所が 1 つと、loadGroup->AddRequestが呼び出される場所が 2 つありloadGroup->RemoveRequestます。

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;
}

重要なことは、と要素の属性streamParse()を調べる を呼び出し、新しいリスナーで新しいチャネルを作成し を呼び出す を呼び出すことです。srcimgscriptauxLoad()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いるため、ロシアの人形のように無限に子アイテムをロードすることもできます。

于 2009-07-02T08:17:31.083 に答える