2017-06-21 17 views
1

私はCompositeByteBufにHTTP要求を構成するいくつかのバッファがあり、HTTP要求行の直後に追加のHTTPヘッダーフィールドを挿入したいと思います。 (私はHTTPのエンコーダ/デコーダ全体を使用したくないのです。なぜなら、私はちょうどデータをプロキシしており、HTTPとしてすべて解析する必要がないからです)。Netty CompositeByteBufの途中に文字列を挿入する方法

派生バッファを使用してこれを行うにはどうすればよいのですか?CompositeByteBufの内容をコピーしないでください。スライスとreadSliceを使って行ったすべての試みは、indexoutofboundsエラーまたはスタックオーバーフローを引き起こしました。誰もが、compositebytebuf全体のコピーを必要としない、次の代替案を提案することはできますか?

/** 
* Injects an XFF header into pendingBuf 
*/ 
private void addXForwardedForHeaderToPendingBuf(
       int pLFpos, 
       String pRemoteIPaddr) 
{ 
    //create a new buffer 
    ByteBuf newBuf = inboundChannel.alloc().directBuffer(); 

    //add the HTTP request line to it 
    ByteBufUtil.writeUtf8(newBuf, 
          pendingBuf.readCharSequence(pLFpos + 1, 
          CharsetUtil.UTF_8)); 

    //add the XFF header 
    ByteBufUtil.writeUtf8(newBuf, "X-Forwarded-For: "); 
    ByteBufUtil.writeUtf8(newBuf, pRemoteIPaddr); 
    ByteBufUtil.writeUtf8(newBuf, "\r\n"); 

    //add anything from the original buffer that came after the request line 
    int bytesRemaining = pendingBuf.readableBytes(); 
    if (bytesRemaining > 0) 
    { 
     newBuf.writeBytes(pendingBuf); 
    } 

    //clear pendingBuf 
    pendingBuf.removeComponents(0, pendingBuf.numComponents()); 
    pendingBuf.setIndex(0, 0); 

    //add newBuf into pendingBuf 
    pendingBuf.addComponent(newBuf); 
    pendingBuf.writerIndex(pendingBuf.writerIndex() + newBuf.writerIndex()); 
} 

答えて

0

現在bytebufの編集中にすべてのバイトが移動する必要がある最悪の場合には、我々はCompositeByteBufは我々が編集し、必要に応じて動き回ることができコンポーネントを持っているという事実を利用することができないという欠点があります。

私たちは、基本的に次のステップを実装する:

  1. 複数bytebuf s inside a CompositeByteBuf`があるかもしれませんので、我々は、変更したいBUFのインデックスを検索したいです。挿入でありますとき

    、これらの方法は、場合には正しく動作しません。私たちはこれを実行するため

    ByteBufは以下のメソッドを提供しますこの文字列の最後は、技術的には元のバッファの範囲外であるため、特別なケースを追加する必要がありました。

  2. これらの場合、実際にゼロコピーで作業できるため、複数のバッファの境界に正確に挿入する特殊なケースを実装します。

  3. 分割インデックスがbytebufの真ん中にある場合、それを分割して2つの別々のバッファーとして追加する必要があります。
  4. 私たちは、上記のフローを使用してfor some reason this doesn't happen by default.

、複合の作家のインデックスを更新する必要があり、我々は次のコードを作成することができます。このコードは非常に複雑であるので

public static void insertString(CompositeByteBuf buffer, int index, ByteBuf insertion) { 
    try { 
     if (buffer == null) { 
      throw new NullPointerException("buffer"); 
     } 
     if (insertion == null) { 
      throw new NullPointerException("insertion"); 
     } 
     if (buffer.readableBytes() < index) { 
      throw new IllegalArgumentException("buffer.readableBytes() < index: " 
        + buffer.readableBytes() + " < " + index); 
     } 

     // Start by checking the offset where we need to inject the insertion 
     int injectionBufOffset; 
     int injectionByteOffset; 
     if (index == buffer.readableBytes()) { 
      injectionBufOffset = buffer.numComponents(); 
      injectionByteOffset = 0; 
     } else { 
      injectionBufOffset = buffer.toComponentIndex(index); 
      injectionByteOffset = index - buffer.toByteIndex(injectionBufOffset); 
     } 

     // Optimalize in the case of offset 0 
     if (injectionByteOffset == 0) { 
      buffer.addComponent(injectionBufOffset, insertion.retain()); 
      buffer.writerIndex(buffer.writerIndex() + insertion.readableBytes()); 
      return; 
     } 
     // Do the split technique 
     ByteBuf toSplit = buffer.internalComponent(injectionBufOffset).retain(); 
     try { 
      buffer.removeComponent(injectionBufOffset); 
      buffer.addComponent(injectionBufOffset + 0, 
        toSplit.readSlice(injectionByteOffset).retain()); 
      buffer.addComponent(injectionBufOffset + 1, insertion.retain()); 
      buffer.addComponent(injectionBufOffset + 2, 
        toSplit.retain()); 
      buffer.writerIndex(buffer.writerIndex() + insertion.readableBytes()); 
     } finally { 
      ReferenceCountUtil.release(toSplit); 
     } 
    } finally { 
     if (insertion != null) { 
      ReferenceCountUtil.release(insertion); 
     } 
    } 
} 

を、我々はまたしたいですしたがって、適切にテストされているかどうかを確認するために、ユニットテスト(JUnit)が必要です:

import static test.NettySplit.insertString; 

public class NettySplitTest { 

    CompositeByteBuf buffer; 
    ByteBuf test; 

    private void addByteBuf(CompositeByteBuf target, ByteBuf source) { 
     target.addComponent(source); 
     target.writerIndex(target.writerIndex() + source.readableBytes()); 
    } 

    @Before 
    public void before() { 
     buffer = ByteBufAllocator.DEFAULT.compositeBuffer(); 
    } 

    @After 
    public void after() { 
     ReferenceCountUtil.release(buffer); 
     buffer = null; 
     ReferenceCountUtil.release(test); 
     test = null; 
    } 

    @Test 
    public void testSplitting() { 
     addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3})); 

     insertString(buffer, 2, Unpooled.wrappedBuffer(new byte[]{5})); 

     test = Unpooled.wrappedBuffer(new byte[]{0, 1, 5, 2, 3}); 
     assertEquals(test, buffer); 

    } 

    @Test 
    public void testInsertionStart() { 
     addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3})); 

     insertString(buffer, 0, Unpooled.wrappedBuffer(new byte[]{5})); 

     test = Unpooled.wrappedBuffer(new byte[]{5, 0, 1, 2, 3}); 
     assertEquals(test, buffer); 
    } 

    @Test 
    public void testInsertionEnd() { 
     addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3})); 

     insertString(buffer, 4, Unpooled.wrappedBuffer(new byte[]{5})); 

     test = Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3, 5}); 
     assertEquals(test, buffer); 
    } 

    @Test 
    public void testInsertionSplitEnd() { 
     addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3})); 
     addByteBuf(buffer, Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3})); 

     insertString(buffer, 6, Unpooled.wrappedBuffer(new byte[]{5})); 

     test = Unpooled.wrappedBuffer(new byte[]{0, 1, 2, 3, 0, 1, 5, 2, 3}); 
     assertEquals(test, buffer); 
    } 

} 
+0

ワウ、今私はそれを理解することができないと感じていません私自身。それでも、私の本能が正しいことを知り、それを効率的に行うことができます。思慮深く答えてくれてありがとう! –

関連する問題