@@ -21,7 +21,7 @@ import java.io.File
2121
2222import org .eclipse .jetty .util .security .{Constraint , Password }
2323import org .eclipse .jetty .security .authentication .DigestAuthenticator
24- import org .eclipse .jetty .security .{ConstraintMapping , ConstraintSecurityHandler , HashLoginService , SecurityHandler }
24+ import org .eclipse .jetty .security .{ConstraintMapping , ConstraintSecurityHandler , HashLoginService }
2525
2626import org .eclipse .jetty .server .Server
2727import org .eclipse .jetty .server .bio .SocketConnector
@@ -41,48 +41,68 @@ private[spark] class ServerStateException(message: String) extends Exception(mes
4141 * as well as classes created by the interpreter when the user types in code. This is just a wrapper
4242 * around a Jetty server.
4343 */
44- private [spark] class HttpServer (resourceBase : File , securityManager : SecurityManager )
45- extends Logging {
44+ private [spark] class HttpServer (
45+ resourceBase : File ,
46+ securityManager : SecurityManager ,
47+ requestedPort : Int = 0 ,
48+ serverName : String = " HTTP server" )
49+ extends Logging {
50+
4651 private var server : Server = null
47- private var port : Int = - 1
52+ private var port : Int = requestedPort
4853
4954 def start () {
5055 if (server != null ) {
5156 throw new ServerStateException (" Server is already started" )
5257 } else {
5358 logInfo(" Starting HTTP Server" )
54- server = new Server ()
55- val connector = new SocketConnector
56- connector.setMaxIdleTime(60 * 1000 )
57- connector.setSoLingerTime(- 1 )
58- connector.setPort(0 )
59- server.addConnector(connector)
60-
61- val threadPool = new QueuedThreadPool
62- threadPool.setDaemon(true )
63- server.setThreadPool(threadPool)
64- val resHandler = new ResourceHandler
65- resHandler.setResourceBase(resourceBase.getAbsolutePath)
66-
67- val handlerList = new HandlerList
68- handlerList.setHandlers(Array (resHandler, new DefaultHandler ))
69-
70- if (securityManager.isAuthenticationEnabled()) {
71- logDebug(" HttpServer is using security" )
72- val sh = setupSecurityHandler(securityManager)
73- // make sure we go through security handler to get resources
74- sh.setHandler(handlerList)
75- server.setHandler(sh)
76- } else {
77- logDebug(" HttpServer is not using security" )
78- server.setHandler(handlerList)
79- }
80-
81- server.start()
82- port = server.getConnectors()(0 ).getLocalPort()
59+ val (actualServer, actualPort) =
60+ Utils .startServiceOnPort[Server ](requestedPort, doStart, serverName)
61+ server = actualServer
62+ port = actualPort
8363 }
8464 }
8565
66+ /**
67+ * Actually start the HTTP server on the given port.
68+ *
69+ * Note that this is only best effort in the sense that we may end up binding to a nearby port
70+ * in the event of port collision. Return the bound server and the actual port used.
71+ */
72+ private def doStart (startPort : Int ): (Server , Int ) = {
73+ val server = new Server ()
74+ val connector = new SocketConnector
75+ connector.setMaxIdleTime(60 * 1000 )
76+ connector.setSoLingerTime(- 1 )
77+ connector.setPort(startPort)
78+ server.addConnector(connector)
79+
80+ val threadPool = new QueuedThreadPool
81+ threadPool.setDaemon(true )
82+ server.setThreadPool(threadPool)
83+ val resHandler = new ResourceHandler
84+ resHandler.setResourceBase(resourceBase.getAbsolutePath)
85+
86+ val handlerList = new HandlerList
87+ handlerList.setHandlers(Array (resHandler, new DefaultHandler ))
88+
89+ if (securityManager.isAuthenticationEnabled()) {
90+ logDebug(" HttpServer is using security" )
91+ val sh = setupSecurityHandler(securityManager)
92+ // make sure we go through security handler to get resources
93+ sh.setHandler(handlerList)
94+ server.setHandler(sh)
95+ } else {
96+ logDebug(" HttpServer is not using security" )
97+ server.setHandler(handlerList)
98+ }
99+
100+ server.start()
101+ val actualPort = server.getConnectors()(0 ).getLocalPort
102+
103+ (server, actualPort)
104+ }
105+
86106 /**
87107 * Setup Jetty to the HashLoginService using a single user with our
88108 * shared secret. Configure it to use DIGEST-MD5 authentication so that the password
@@ -134,7 +154,7 @@ private[spark] class HttpServer(resourceBase: File, securityManager: SecurityMan
134154 if (server == null ) {
135155 throw new ServerStateException (" Server is not started" )
136156 } else {
137- return " http://" + Utils .localIpAddress + " :" + port
157+ " http://" + Utils .localIpAddress + " :" + port
138158 }
139159 }
140160}
0 commit comments