前回、HTTPのchunkごと(がわかるように)の受信を調べてみた。
やはり、URLStreamではできないことがわかった。

データの中身をみて、できていないのだからできないのだろうが、
Content-Typeかなんかに違いがあるのかなとも思い始めたので、
BlazeDSのソースをみてみることにした。
で、簡単にだめだというのでつまらないので、私なりの調べ方を記しておく。

ソースをダウンロードしてみて、

find ./ | grep java$ | xargs grep -i -n "chunked"

とやってみると、

./modules/core/src/flex/messaging/endpoints/BaseStreamingHTTPEndpoint.java:71:     * This token is used in chunked HTTP responses frequently so initialize it statically for general use.
./modules/core/src/flex/messaging/endpoints/BaseStreamingHTTPEndpoint.java:76:     * This token is used for the terminal chunk within a chunked response.
./modules/core/src/flex/messaging/endpoints/BaseStreamingHTTPEndpoint.java:719:                res.setHeader("Transfer-Encoding", "chunked");
./modules/core/src/flex/messaging/endpoints/BaseStreamingHTTPEndpoint.java:1063:     * "Transfer-Encoding: chunked" format.
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:79:    private static final String CONTENT_CHUNKED = "content-chunked";
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:88:    protected boolean contentChunked = false;
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:169:     *  <content-chunked>false</content-chunked>
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:374:        // Content Chunked
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:375:        if (properties.getProperty(CONTENT_CHUNKED) != null)
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:377:            boolean ch = properties.getPropertyAsBoolean(CONTENT_CHUNKED, false);
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:378:            setContentChunked(ch);
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:432:     * Returns the <code>content-chunked</code> property.
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:434:     * @return <code>true</code> if <code>content-chunked</code> property is
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:437:    public boolean isContentChunked()
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:439:        return contentChunked;
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:443:     * Sets the <code>content-chunked</code> property. Default <code>false</code>.
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:445:     * @param contentChunked The <code>content-chunked</code> property.
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:447:    public void setContentChunked(boolean contentChunked)
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:449:        this.contentChunked = contentChunked;
./modules/proxy/src/flex/messaging/services/http/HTTPProxyAdapter.java:596:        context.setContentChunked(contentChunked);
./modules/proxy/src/flex/messaging/services/http/proxy/ProxyContext.java:52:    private boolean contentChunked;
./modules/proxy/src/flex/messaging/services/http/proxy/ProxyContext.java:227:    public boolean getContentChunked()
./modules/proxy/src/flex/messaging/services/http/proxy/ProxyContext.java:229:        return contentChunked;
./modules/proxy/src/flex/messaging/services/http/proxy/ProxyContext.java:232:    public void setContentChunked(boolean value)
./modules/proxy/src/flex/messaging/services/http/proxy/ProxyContext.java:234:        contentChunked = value;
./modules/proxy/src/flex/messaging/services/http/proxy/RequestFilter.java:165:            ((EntityEnclosingMethod)httpMethod).setContentChunked(context.getContentChunked());

これで、対象のソースは
flex/messaging/endpoints/BaseStreamingHTTPEndpoint.java
しかないことがわかる。
res.setHeader(“Transfer-Encoding”, “chunked”);
とTransfer-Encodingに設定しているところがここしかないからである。

こんか感じに、私はソースを調べる場合にはたいてい、linuxなどのshellが使える環境で探す。
それでもって、ソースをみるもの、viewコマンドでみていく。
なぜなら、検索がらくなので、書くのはEclipse、みるのはviewコマンドが私なりの開発手法です。

さて、話は戻って、
怪しそうな場所を抜粋すると、

            try
            {
                currentThread.setName(threadName + STREAMING_THREAD_NAME_EXTENSION);

                // Open and commit response headers and get output stream.
                if (addNoCacheHeaders)
                    addNoCacheHeaders(req, res);
                res.setContentType(getResponseContentType());
                res.setHeader("Connection", "close");
                res.setHeader("Transfer-Encoding", "chunked");
                ServletOutputStream os = res.getOutputStream();
                res.flushBuffer();

                // If kickstart-bytes are specified, stream them.
                if (kickStartBytesToStream != null)
                {
                    if (Log.isDebug())
                        log.debug("Endpoint with id '" + getId() + "' is streaming " + kickStartBytesToStream.length
                                + " bytes (not counting chunk encoding overhead) to kick-start the streaming connection for FlexClient with id '"
                                + flexClient.getId() + "'.");

                    streamChunk(kickStartBytesToStream, os, res);
                }

とこんな感じ。
最後のstreamChunkでデータを書き出していそうだ。
では、kickStartBytesToStreamという変数があるが、これがそのためのデータっぽい感じだ。
そして、そのメソッドの中身をみてみれば・・

    protected void streamChunk(byte[] bytes, ServletOutputStream os, HttpServletResponse response) throws IOException
    {
        if ((bytes != null) && (bytes.length > 0))
        {
            byte[] chunkLength = Integer.toHexString(bytes.length).getBytes("ASCII");
            os.write(chunkLength);
            os.write(CRLF_BYTES);
            os.write(bytes);
            os.write(CRLF_BYTES);
            response.flushBuffer();
        }
        else // Send final 'EOF' chunk for the response.
        {
            os.write(ZERO_BYTE);
            os.write(CRLF_BYTES);
            response.flushBuffer();
        }
    }

やはり、データをチャンクとして書き出している。
この中でちゃんとチャンクの長さも調べている。

で、kickStartBytesStreamを調べてみると、

int kickStartBytes = agentSettings.getKickstartBytes();
                if (kickStartBytes > 0)
                {
                    // Determine the minimum number of actual bytes that need to be sent to
                    // kickstart, taking into account transfer-encoding overhead.
                    try
                    {
                        int chunkLengthHeaderSize = Integer.toHexString(kickStartBytes).getBytes("ASCII").length;
                        int chunkOverhead = chunkLengthHeaderSize + 4; // 4 for the 2 wrapping CRLF tokens.
                        int minimumKickstartBytes = kickStartBytes - chunkOverhead;
                        kickStartBytesToStream = new byte[(minimumKickstartBytes > 0) ? minimumKickstartBytes :
                                kickStartBytes];
                    }
                    catch (UnsupportedEncodingException ignore)
                    {
                        kickStartBytesToStream = new byte[kickStartBytes];
                    }
                    Arrays.fill(kickStartBytesToStream, NULL_BYTE);
                }

と、あれれ・・・
なんらかのデータの長さをチャンクデータとして書き出している。
つまり、最初にChunkデータとして、次のChunkデータサイズを出力し、
次にデータそのものを送っている感じだ。

あー、やっぱり。
だからStreamingConnectionHandlerというflexのクラスの方では、
Chunkサイズがとれていたのですね。
これで、送り元と受信先のプログラムのロジックが一致しました。

あー紛らわし。
できれば、先頭xxバイトはデータの長さとか別のルールにしておいてくれれば・・・

そんなこんなで、結局、
ActionScriptでChunkごとのデータを受信して、Server-Sent Eventのようにするには、
データのデリミタをデータフォーマットの定義として必要にしないといけないようです。

Flexでも、JavaScriptでもどっちでも使えるようにデータ送信方法を設計したかったので、
chunkごとの切れ目がわかればよかったのですが、あきらめるしかないようです。

お仕事のご依頼・相談を承ります
この記事に関連するお仕事のご依頼やご相談をお待ちしております。 詳しくは、こちら

Leave a Reply

お仕事のご依頼・相談
この記事に関連するお仕事のご依頼やご相談をお待ちしております。 詳しくは、こちら
ソフトウェア&ライブラリ




ライブラリ
airxmail(en)
AIR版メール送受信ライブラリ
airxzip
AIR版ZIP圧縮・解凍ライブラリ
執筆書籍
本、雑誌等

WEB記事:CodeZine
執筆記事はこちら
カレンダー
2012年1月
« 12月   2月 »
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

カスタム検索
RSS
Add to Google < !–adsense–>
アーカイブ
カテゴリ
にほんブログ村 IT技術ブログへ