///|
// The engine closes every response after writing it (also for HEAD/204 and
// failures). A private body lease therefore tracks the whole response, not
// just the handler call, without adding runtime hooks to the portable engine.
priv struct ResponseLease {
  body : @http.Body
  done : () -> Unit
  mut reader : &@http.BodyStream?
  mut sent : Bool
  mut closed : Bool
}

///|
impl @http.BodyStream for ResponseLease with fn read_some(self) {
  if self.closed {
    return None
  }
  match self.body {
    Stream(cell) => {
      let reader = match self.reader {
        Some(reader) => reader
        None => {
          let reader = cell.take()
          self.reader = Some(reader)
          reader
        }
      }
      reader.read_some()
    }
    _ => {
      if self.sent {
        return None
      }
      self.sent = true
      match self.body.as_bytes() {
        Some(bytes) if !bytes.is_empty() => Some(bytes)
        _ => None
      }
    }
  }
}

///|
impl @http.BodyStream for ResponseLease with fn close(self) {
  if !self.closed {
    self.closed = true
    match self.reader {
      Some(reader) => reader.close()
      None => if self.body is Stream(cell) { cell.close() }
    }
    (self.done)()
  }
}

///|
fn lease(
  response : @http.Response,
  meth : @http.Method,
  done : () -> Unit,
) -> @http.Response {
  {
    ..response,
    body: Stream(
      @http.StreamBody::new(
        ResponseLease::{
          body: response.body,
          done,
          reader: None,
          sent: false,
          closed: false,
        },
        // Empty on HEAD/304 describes no representation length. Keep the
        // engine's NoBody framing instead of inventing Content-Length: 0.
        length?=if response.body is Empty &&
          (meth == Head || response.status == 304) {
          None
        } else {
          response.body.length()
        },
      ),
    ),
  }
}