Permalink
Browse files

! can: only render default User-Agent if no such header was explicit

given, fixes #462
  • Loading branch information...
jrudolph committed Sep 18, 2013
1 parent 654a77b commit 6fec00c89a6569c1da5ec54f55e9149547fa3c59
@@ -95,8 +95,8 @@ headers.
Additionally *spray-can* will render a
- ``Host`` request header if none is explicitly added.
-- ``User-Agent`` header if one is configured. If none is configured an explicitly added added ``User-Agent`` header is
- also rendered.
+- ``User-Agent`` default request header if none is explicitly defined. The default value can be configured with the
+ ``spray.can.client.user-agent-header`` configuration setting.
.. note:: The ``Content-Type`` header has special status in *spray* since its value is part of the ``HttpEntity`` model
class. Even though the header also remains in the ``headers`` list of the ``HttpResponse`` *sprays* higher layers
@@ -142,8 +142,8 @@ class RequestRendererSpec extends Specification {
"GET request with overridden User-Agent and without body" in new TestSetup(Some(`User-Agent`("settings-ua/1.0"))) {
HttpRequest(GET, "/abc", List(RawHeader("User-Agent", "user-ua/1.0"))) must beRenderedTo {
"""GET /abc HTTP/1.1
+ |User-Agent: user-ua/1.0
|Host: test.com:8080
- |User-Agent: settings-ua/1.0
|
|"""
}
@@ -157,9 +157,10 @@ spray.can {
}
client {
- # The value of the `User-Agent` header to produce.
- # Set to the empty string to disable automatic rendering of the
- # `User-Agent` header.
+ # The default value of the `User-Agent` header to produce if no
+ # explicit `User-Agent`-header was included in a request.
+ # If this value is the empty string and no header was included in
+ # the request, no `User-Agent` header will be rendered at all.
user-agent-header = spray-can/${spray.version}
# The time after which an idle connection will be automatically closed.
@@ -31,29 +31,29 @@ trait RequestRenderingComponent {
log: LoggingAdapter): Unit = {
def renderRequestStart(request: HttpRequest): Unit = {
import request._
- @tailrec def renderHeaders(remaining: List[HttpHeader], hostHeaderSeen: Boolean = false): Unit =
+ @tailrec def renderHeaders(remaining: List[HttpHeader], hostHeaderSeen: Boolean = false, userAgentSeen: Boolean = false): Unit =
remaining match {
- case Nil if (!hostHeaderSeen) r ~~ Host(serverAddress) ~~ CrLf
+ case Nil
+ if (!hostHeaderSeen) r ~~ Host(serverAddress) ~~ CrLf
+ if (!userAgentSeen && userAgent.isDefined) r ~~ userAgent.get ~~ CrLf
case head :: tail
- def logHeaderSuppressionWarning(msg: String): Boolean = {
+ def logHeaderSuppressionWarning(msg: String): Unit =
log.warning("Explicitly set request header '{}' is ignored, {}", head, msg)
- false
- }
- val found = head.lowercaseName match {
+
+ head.lowercaseName match {
case "content-type" if entity.nonEmpty
logHeaderSuppressionWarning("the request Content-Type is set via the request's HttpEntity!")
+ renderHeaders(tail, hostHeaderSeen, userAgentSeen)
case "content-length" | "transfer-encoding"
logHeaderSuppressionWarning("the spray-can HTTP layer sets this header automatically!")
- case "user-agent" if userAgent.isDefined
- logHeaderSuppressionWarning("the configured User-Agent header overrides the given one!")
- case "host" r ~~ head ~~ CrLf; true
- case _ r ~~ head ~~ CrLf; false
+ renderHeaders(tail, hostHeaderSeen, userAgentSeen)
+ case "user-agent" r ~~ head ~~ CrLf; renderHeaders(tail, hostHeaderSeen, userAgentSeen = true)
+ case "host" r ~~ head ~~ CrLf; renderHeaders(tail, hostHeaderSeen = true, userAgentSeen)
+ case _ r ~~ head ~~ CrLf; renderHeaders(tail, hostHeaderSeen, userAgentSeen)
}
- renderHeaders(tail, found || hostHeaderSeen)
}
uri.renderWithoutFragment(r ~~ request.method ~~ ' ', UTF8) ~~ ' ' ~~ protocol ~~ CrLf
renderHeaders(headers)
- if (userAgent.isDefined) r ~~ userAgent.get ~~ CrLf
entity match {
case HttpEntity.NonEmpty(ContentTypes.NoContentType, _) | HttpEntity.Empty // don't render Content-Type header
case HttpEntity.NonEmpty(contentType, _) r ~~ `Content-Type` ~~ contentType ~~ CrLf

0 comments on commit 6fec00c

Please sign in to comment.