/
Server.scala
163 lines (143 loc) · 5.71 KB
/
Server.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
* Copyright (C) 2009-2016 Lightbend Inc. <https://www.lightbend.com>
*/
package play.core.server
import com.typesafe.config.ConfigFactory
import play.api.http.{ Port, DefaultHttpErrorHandler }
import play.api.routing.Router
import scala.language.postfixOps
import play.api._
import play.api.mvc._
import play.core.{ DefaultWebCommands, ApplicationProvider }
import scala.util.{ Success, Failure }
import scala.concurrent.Future
trait WebSocketable {
def getHeader(header: String): String
def check: Boolean
}
/**
* Provides generic server behaviour for Play applications.
*/
trait Server extends ServerWithStop {
def mode: Mode.Mode
/**
* Try to get the handler for a request and return it as a `Right`. If we
* can't get the handler for some reason then return a result immediately
* as a `Left`. Reasons to return a `Left` value:
*
* - If there's a "web command" installed that intercepts the request.
* - If we fail to get the `Application` from the `applicationProvider`,
* i.e. if there's an error loading the application.
* - If an exception is thrown.
*/
def getHandlerFor(request: RequestHeader): Either[Future[Result], (RequestHeader, Handler, Application)] = {
// Common code for handling an exception and returning an error result
def logExceptionAndGetResult(e: Throwable): Left[Future[Result], Nothing] = {
Left(DefaultHttpErrorHandler.onServerError(request, e))
}
try {
applicationProvider.handleWebCommand(request) match {
case Some(result) =>
Left(Future.successful(result))
case None =>
applicationProvider.get match {
case Success(application) =>
application.requestHandler.handlerForRequest(request) match {
case (requestHeader, handler) => Right((requestHeader, handler, application))
}
case Failure(e) => logExceptionAndGetResult(e)
}
}
} catch {
case e: ThreadDeath => throw e
case e: VirtualMachineError => throw e
case e: Throwable =>
logExceptionAndGetResult(e)
}
}
def applicationProvider: ApplicationProvider
def stop() {
applicationProvider.current.foreach { app =>
LoggerConfigurator(app.classloader).foreach(_.shutdown())
}
}
/**
* Returns the HTTP port of the server.
*
* This is useful when the port number has been automatically selected (by setting a port number of 0).
*
* @return The HTTP port the server is bound to, if the HTTP connector is enabled.
*/
def httpPort: Option[Int]
/**
* Returns the HTTPS port of the server.
*
* This is useful when the port number has been automatically selected (by setting a port number of 0).
*
* @return The HTTPS port the server is bound to, if the HTTPS connector is enabled.
*/
def httpsPort: Option[Int]
}
/**
* Utilities for creating a server that runs around a block of code.
*/
object Server {
/**
* Run a block of code with a server for the given application.
*
* The passed in block takes the port that the application is running on. By default, this will be a random ephemeral
* port. This can be changed by passing in an explicit port with the config parameter.
*
* @param application The application for the server to server.
* @param config The configuration for the server. Defaults to test config with the http port bound to a random
* ephemeral port.
* @param block The block of code to run.
* @param provider The server provider.
* @return The result of the block of code.
*/
def withApplication[T](application: Application, config: ServerConfig = ServerConfig(port = Some(0), mode = Mode.Test))(block: Port => T)(implicit provider: ServerProvider): T = {
Play.start(application)
val server = provider.createServer(config, application)
try {
block(new Port((server.httpPort orElse server.httpsPort).get))
} finally {
server.stop()
}
}
/**
* Run a block of code with a server for the given routes.
*
* The passed in block takes the port that the application is running on. By default, this will be a random ephemeral
* port. This can be changed by passing in an explicit port with the config parameter.
*
* @param routes The routes for the server to server.
* @param config The configuration for the server. Defaults to test config with the http port bound to a random
* ephemeral port.
* @param block The block of code to run.
* @param provider The server provider.
* @return The result of the block of code.
*/
def withRouter[T](config: ServerConfig = ServerConfig(port = Some(0), mode = Mode.Test))(routes: PartialFunction[RequestHeader, Handler])(block: Port => T)(implicit provider: ServerProvider): T = {
val application = new BuiltInComponentsFromContext(ApplicationLoader.Context(
Environment.simple(path = config.rootDir, mode = config.mode),
None, new DefaultWebCommands(), Configuration(ConfigFactory.load())
)) {
def router = Router.from(routes)
}.application
withApplication(application, config)(block)
}
}
private[play] object JavaServerHelper {
def forRouter(router: Router, mode: Mode.Mode, httpPort: Option[Integer], sslPort: Option[Integer]): Server = {
val r = router
val application = new BuiltInComponentsFromContext(ApplicationLoader.Context(
Environment.simple(mode = mode),
None, new DefaultWebCommands(), Configuration(ConfigFactory.load())
)) {
def router = r
}.application
Play.start(application)
val serverConfig = ServerConfig(mode = mode, port = httpPort.map(_.intValue), sslPort = sslPort.map(_.intValue))
implicitly[ServerProvider].createServer(serverConfig, application)
}
}