aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/scala/com/softwaremill/sttp/HttpConnectionSttpHandler.scala
blob: f2d55271a612425a710152118a0896080756d792 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.softwaremill.sttp

import java.io.{InputStream, OutputStream, OutputStreamWriter}
import java.net.HttpURLConnection
import java.nio.channels.Channels
import java.nio.file.Files

import scala.annotation.tailrec

class HttpConnectionSttpHandler extends SttpHandler[Id] {
  override def send[T](r: Request, responseReader: ResponseBodyReader[T]): Response[T] = {
    val c = r.uri.toURL.openConnection().asInstanceOf[HttpURLConnection]
    c.setRequestMethod(r.method.m)
    r.headers.foreach { case (k, v) => c.setRequestProperty(k, v) }
    c.setDoInput(true)
    setBody(r, c)

    val status = c.getResponseCode
    Response(status, responseReader.fromInputStream(c.getInputStream))
  }

  private def setBody(r: Request, c: HttpURLConnection): Unit = {
    if (r.body != NoBody) c.setDoOutput(true)

    def copyStream(in: InputStream, out: OutputStream): Unit = {
      val buf = new Array[Byte](1024)

      @tailrec
      def doCopy(): Unit = {
        val read = in.read(buf)
        if (read != -1) {
          out.write(buf, 0, read)
          doCopy()
        }
      }

      doCopy()
    }

    r.body match {
      case NoBody => // skip

      case StringBody(b) =>
        val writer = new OutputStreamWriter(c.getOutputStream)
        try writer.write(b) finally writer.close()

      case ByteArrayBody(b) =>
        c.getOutputStream.write(b)

      case ByteBufferBody(b) =>
        val channel = Channels.newChannel(c.getOutputStream)
        try channel.write(b) finally channel.close()

      case InputStreamBody(b) =>
        copyStream(b, c.getOutputStream)

      case InputStreamSupplierBody(b) =>
        copyStream(b(), c.getOutputStream)

      case FileBody(b) =>
        Files.copy(b.toPath, c.getOutputStream)

      case PathBody(b) =>
        Files.copy(b, c.getOutputStream)
    }
  }
}