前回、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ごとの切れ目がわかればよかったのですが、あきらめるしかないようです。


