/
Headers.scala
125 lines (100 loc) · 4.6 KB
/
Headers.scala
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package org.http4s
import cats.Show
import cats.syntax.show._
import org.http4s.HeaderKey.StringKey
import org.http4s.util.CaseInsensitiveString
import org.http4s.headers.`Set-Cookie`
import scala.collection.{GenTraversableOnce, immutable, mutable}
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.ListBuffer
/** A collection of HTTP Headers */
final class Headers private (headers: List[Header])
extends immutable.Iterable[Header]
with collection.IterableLike[Header, Headers]
{
override def toList: List[Header] = headers
override def isEmpty: Boolean = headers.isEmpty
override protected def newBuilder: mutable.Builder[Header, Headers] = Headers.newBuilder
override def drop(n: Int): Headers = if (n == 0) this else new Headers(headers.drop(n))
override def head: Header = headers.head
override def foreach[B](f: Header => B): Unit = headers.foreach(f)
def iterator: Iterator[Header] = headers.iterator
/** Attempt to get a [[org.http4s.Header]] of type key.HeaderT from this collection
*
* @param key [[HeaderKey.Extractable]] that can identify the required header
* @return a scala.Option possibly containing the resulting header of type key.HeaderT
* @see [[Header]] object and get([[org.http4s.util.CaseInsensitiveString]])
*/
def get(key: HeaderKey.Extractable): Option[key.HeaderT] = key.from(this)
/** Attempt to get a [[org.http4s.Header]] from this collection of headers
*
* @param key name of the header to find
* @return a scala.Option possibly containing the resulting [[org.http4s.Header]]
*/
def get(key: CaseInsensitiveString): Option[Header] = headers.find(_.name == key)
/** Make a new collection adding the specified headers, replacing existing headers of singleton type
* The passed headers are assumed to contain no duplicate Singleton headers.
*
* @param in multiple [[Header]] to append to the new collection
* @return a new [[Headers]] containing the sum of the initial and input headers
*/
def put(in: Header*): Headers = {
if (in.isEmpty) this
else if (this.isEmpty) new Headers(in.toList)
else this ++ in
}
/** Concatenate the two collections
* If the resulting collection is of Headers type, duplicate Singleton headers will be removed from
* this Headers collection.
*
* @param that collection to append
* @tparam B type contained in collection `that`
* @tparam That resulting type of the new collection
*/
override def ++[B >: Header, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[Headers, B, That]): That = {
if (bf eq Headers.canBuildFrom) { // Making a new Headers collection from a collection of Header's
if (that.isEmpty) this.asInstanceOf[That]
else if (this.isEmpty) that match {
case hs: Headers => hs.asInstanceOf[That]
case hs => new Headers(hs.toList.asInstanceOf[List[Header]]).asInstanceOf[That]
}
else {
val hs = that.toList.asInstanceOf[List[Header]]
val acc = new ListBuffer[Header]
this.headers.foreach { orig => orig.parsed match {
case h: Header.Recurring => acc += orig
case h: `Set-Cookie` => acc += orig
case h if !hs.exists(_.name == h.name) => acc += orig
case _ => // NOOP, drop non recurring header that already exists
}}
val h = new Headers(acc.prependToList(hs))
h.asInstanceOf[That]
}
}
else super.++(that)
}
override def hashCode(): Int = this.headers.hashCode()
override def equals(that: Any): Boolean = that match {
case otherheaders: Headers =>
this.toList.equals(otherheaders.toList)
case _ => false
}
}
object Headers {
val empty = apply()
/** Create a new Headers collection from the headers */
def apply(headers: Header*): Headers = Headers(headers.toList)
/** Create a new Headers collection from the headers */
def apply(headers: List[Header]): Headers = new Headers(headers)
implicit val canBuildFrom: CanBuildFrom[Traversable[Header], Header, Headers] =
new CanBuildFrom[TraversableOnce[Header], Header, Headers] {
def apply(from: TraversableOnce[Header]): mutable.Builder[Header, Headers] = newBuilder
def apply(): mutable.Builder[Header, Headers] = newBuilder
}
private def newBuilder: mutable.Builder[Header, Headers] =
new mutable.ListBuffer[Header] mapResult (b => new Headers(b))
implicit val headersShow: Show[Headers] =
new Show[Headers]{
def show(f: Headers): String = f.iterator.map(_.show).mkString("Headers(", ", ", ")")
}
}