All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twitter.finagle.netty4.http.Netty4HttpCodec.scala Maven / Gradle / Ivy

package com.twitter.finagle.netty4.http

import com.twitter.finagle.http.{Request, Response}
import com.twitter.finagle.netty4.http.handler.UnpoolHttpHandler
import io.netty.buffer.{ByteBuf, Unpooled}
import io.netty.handler.codec.http._
import java.net.InetSocketAddress
import io.netty.channel.embedded.EmbeddedChannel
import java.nio.charset.{StandardCharsets => Charsets}

/**
 * Utilities for encoding/decoding [[Request]]s and [[Response]]s to/from Strings
 * and byte arrays using Netty4 as the underlying implementation.
 */
private[finagle] object Netty4HttpCodec {

  /** Encode a [[Request]] to a String. */
  def encodeRequestToString(request: Request): String = {
    new String(encodeRequestToBytes(request), "UTF-8")
  }

  /** Encode a [[Request]] to a byte array */
  def encodeRequestToBytes(request: Request): Array[Byte] = {

    val ch = new EmbeddedChannel(
      new HttpRequestEncoder
    )

    ch.writeOneOutbound(Bijections.finagle.requestToNetty(request, request.contentLength))
    ch.flushOutbound()
    val acc = ch.alloc.compositeBuffer()

    try {
      while (!ch.outboundMessages.isEmpty) {
        acc.addComponent(true, ch.readOutbound[ByteBuf]())
      }

      val out = new Array[Byte](acc.readableBytes)
      acc.readBytes(out)
      out
    } finally {
      acc.release()
      ch.finishAndReleaseAll()
    }
  }

  /** Decode a [[Request]] from a String */
  def decodeStringToRequest(s: String): Request = {
    decodeBytesToRequest(s.getBytes(Charsets.UTF_8))
  }

  /** Decode a [[Request]] from a byte array */
  def decodeBytesToRequest(b: Array[Byte]): Request = {
    val ch = new EmbeddedChannel(
      new HttpRequestDecoder(Int.MaxValue, Int.MaxValue, Int.MaxValue),
      new HttpObjectAggregator(Int.MaxValue),
      UnpoolHttpHandler // Make sure nothing is ref-counted
    )

    try {
      ch.writeInbound(Unpooled.wrappedBuffer(b))
      ch.flushInbound()

      // Should be exactly one message or the input data was likely malformed
      // Note: we perform the assert before reading so that the if it fails any
      // messages are still freed in the finally block
      assert(ch.inboundMessages.size == 1)
      val nettyReq = ch.readInbound[FullHttpRequest]()

      Bijections.netty.fullRequestToFinagle(nettyReq, new InetSocketAddress(0))
    } finally {
      ch.finishAndReleaseAll()
    }
  }

  /** Encode a [[Response]] to a String */
  def encodeResponseToString(response: Response): String = {
    val ch = new EmbeddedChannel(
      new HttpResponseEncoder
    )

    val acc = ch.alloc().compositeBuffer()

    try {
      ch.writeOutbound(Bijections.finagle.fullResponseToNetty(response))
      ch.flushOutbound()

      while (!ch.outboundMessages.isEmpty) {
        acc.addComponent(true, ch.readOutbound[ByteBuf]())
      }

      acc.toString(Charsets.UTF_8)
    } finally {
      acc.release()
      ch.finishAndReleaseAll()
    }
  }

  /** Decode a [[Response]] from a String */
  def decodeStringToResponse(s: String): Response = {
    decodeBytesToResponse(s.getBytes(Charsets.UTF_8))
  }

  /** Decode a [[Response]] from a byte array */
  def decodeBytesToResponse(b: Array[Byte]): Response = {
    val ch = new EmbeddedChannel(
      new HttpResponseDecoder(Int.MaxValue, Int.MaxValue, Int.MaxValue),
      new HttpObjectAggregator(Int.MaxValue),
      UnpoolHttpHandler // Make sure nothing is ref-counted
    )

    try {
      ch.writeInbound(Unpooled.wrappedBuffer(b))
      ch.flushInbound()

      // Should be exactly one message or the message was likely malformed
      // Note: we perform the assert before reading so that the if it fails any
      // messages are still freed in the finally block
      assert(ch.inboundMessages.size == 1)
      val resp = ch.readInbound[FullHttpResponse]()

      Bijections.netty.fullResponseToFinagle(resp)
    } finally {
      ch.finishAndReleaseAll()
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy