読者です 読者をやめる 読者になる 読者になる

テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(akka-http report) akka-httpはヘッダについてフレームワークでの制御をsprayより強めている

/**
 * Instances of this class will only be created transiently during header parsing and will never appear
 * in HttpMessage.header. To access the Content-Length, see subclasses of HttpEntity.
 */
final case class `Content-Length` private[http] (length: Long) extends ModeledHeader {
  def renderValue[R <: Rendering](r: R): r.type = r ~~ length
  protected def companion = `Content-Length`
}

CloseDelimitedやChunkedのようなストリーム型のHttpEntityの場合, クライアント側はそれをすべて受け取るまでサイズを計算出来ない. しかしS3の仕様ではContent-Lengthを返さないといけない. (あとで紹介するcontentLengthOptionのコメントはそういうことはdangerousだと書いてあるのに・・)

sprayでは, Content-Lengthをヘッダリストに設定してackしてあげるとこれが実現出来たが, akka-httpではこれがプライベートになっている. 代わりに, レスポンスを作る時にフレームワーク側が分かるなら計算してあげるよということにしている.

sprayやakka-httpは, いくつかのヘッダ(例: Connection)についてフレームワーク側でコントロールすることを好んでいる. sprayからakka-httpに再設計した時に, 色々な反省があったのだと思うが,

CloseDelimitedがContent-Length > 0を返せないとかなり困る. 理由はまず, ストリーム型のレスポンスを返せないと, S3に保存された巨大なファイルを返すことが出来なくなるということ. そして, Chunkedレスポンスは, いくつかのクライアントソフトウェアが対応していないので, akka-httpでいうところのCloseDelimitedで返す必要があるということ. しかし, 以下のコメントから分かるように, StrictとDefault entityでしか設定出来なくなった.

  /**
   * Some(content length) if a length is defined for this entity, None otherwise.
   * A length is only defined for Strict and Default entity types.
   *
   * In many cases it's dangerous to rely on the (non-)existence of a content-length.
   * HTTP intermediaries like (transparent) proxies are allowed to change the transfer-encoding
   * which can result in the entity being delivered as another type as expected.
   */
  def contentLengthOption: Option[Long]

もしかしたら, def apply(contentType: ContentType, file: File, chunkSize: Int = -1): UniversalEntityがうまく動作してくれるかも知れないが, やってみないと分からない.

ちなみにだが, responseWithMediaTypeも消された. これも, HttpEntityの作成時に指定するということになった. 理由は「アンチパターンだと考えたから」だそうだ. https://groups.google.com/forum/#!topic/akka-user/_054Z0G622w/discussion

sprayからakka-httpへの移行は, かなり辛い.