Skip to content

Commit bceb3a9

Browse files
committed
set http response code on error, some testing
1 parent e0356b6 commit bceb3a9

File tree

3 files changed

+78
-21
lines changed

3 files changed

+78
-21
lines changed

core/src/main/scala/org/apache/spark/status/StatusJsonHandler.scala

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
package org.apache.spark.status
1919

20-
import javax.servlet.http.HttpServletRequest
20+
import javax.servlet.http.{HttpServletResponse, HttpServlet, HttpServletRequest}
2121

2222
import com.fasterxml.jackson.annotation.JsonInclude
2323
import com.fasterxml.jackson.databind.{SerializationFeature, ObjectMapper}
@@ -31,8 +31,7 @@ import org.eclipse.jetty.servlet.{ServletHolder, ServletContextHandler}
3131
import scala.util.matching.Regex
3232

3333
import org.apache.spark.{Logging, SecurityManager}
34-
import org.apache.spark.deploy.history.{OneApplicationJsonRoute, HistoryServer, AllApplicationsJsonRoute}
35-
import org.apache.spark.ui.JettyUtils._
34+
import org.apache.spark.deploy.history.{OneApplicationJsonRoute, AllApplicationsJsonRoute}
3635

3736

3837
/**
@@ -60,9 +59,9 @@ private[spark] class JsonRequestHandler(uiRoot: UIRoot, securityManager: Securit
6059
s"/applications/$noSlash+/jobs/?".r -> new AllJobsJsonRoute(this),
6160
s"/applications/$noSlash+/executors/?".r -> new ExecutorsJsonRoute(this),
6261
s"/applications/$noSlash+/stages/?".r -> new AllStagesJsonRoute(this),
63-
s"/applications/$noSlash+/stages/\\d+/?".r -> new OneStageJsonRoute(this),
62+
s"/applications/$noSlash+/stages/$noSlash+/?".r -> new OneStageJsonRoute(this),
6463
s"/applications/$noSlash+/storage/rdd/?".r -> new AllRDDJsonRoute(this),
65-
s"/applications/$noSlash+/storage/rdd/\\d+/?".r -> new RDDJsonRoute(this)
64+
s"/applications/$noSlash+/storage/rdd/$noSlash+/?".r -> new RDDJsonRoute(this)
6665
)
6766

6867
private val jsonMapper = {
@@ -76,17 +75,36 @@ private[spark] class JsonRequestHandler(uiRoot: UIRoot, securityManager: Securit
7675
val jsonContextHandler = {
7776

7877
//TODO throw out all the JettyUtils stuff, so I can set the response status code, etc.
79-
val params = new ServletParams(
80-
{
81-
(request: HttpServletRequest) =>
82-
route(request).map{jsonRoute =>
83-
logInfo("handling route: " + request.getPathInfo)
84-
val responseObj = jsonRoute.renderJson(request)
85-
jsonMapper.writeValueAsString(responseObj)
86-
}.getOrElse(throw new IllegalArgumentException("unmatched route"))
87-
}, "text/json")
78+
val servlet = new HttpServlet {
79+
override def doGet(request: HttpServletRequest, response: HttpServletResponse) {
80+
if (securityManager.checkUIViewPermissions(request.getRemoteUser)) {
81+
response.setContentType("text/json;charset=utf-8")
82+
route(request) match {
83+
case Some(jsonRoute) =>
84+
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate")
85+
try {
86+
val responseObj = jsonRoute.renderJson(request)
87+
val result = jsonMapper.writeValueAsString(responseObj)
88+
response.setStatus(HttpServletResponse.SC_OK)
89+
response.getWriter.println(result)
90+
} catch {
91+
case iae: IllegalArgumentException =>
92+
response.setStatus(HttpServletResponse.SC_BAD_REQUEST)
93+
response.getOutputStream.print(iae.getMessage())
94+
}
95+
case None =>
96+
println("no match for path: " + request.getPathInfo)
97+
response.setStatus(HttpServletResponse.SC_NOT_FOUND)
98+
}
99+
} else {
100+
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED)
101+
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate")
102+
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
103+
"User is not authorized to access this page.")
104+
}
105+
}
106+
}
88107
val path = "/json/v1"
89-
val servlet = createServlet(params, securityManager)
90108
val contextHandler = new ServletContextHandler
91109
val holder = new ServletHolder(servlet)
92110
contextHandler.setContextPath(path)
@@ -148,4 +166,3 @@ object RouteUtils {
148166
}
149167
}
150168
}
151-

core/src/main/scala/org/apache/spark/ui/jobs/OneStageJsonRoute.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class OneStageJsonRoute(parent: JsonRequestHandler) extends StatusJsonRoute[Stag
4545
}
4646
AllStagesJsonRoute.stageUiToStageData(status, stageInfo, stageUiData, includeDetails = true)
4747
case None =>
48-
throw new IllegalArgumentException("no stage found with id:" + stageId)
48+
throw new IllegalArgumentException("unknown stage: " + stageId)
4949
}
5050

5151
case None =>

core/src/test/scala/org/apache/spark/deploy/history/HistoryServerSuite.scala

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
*/
1717
package org.apache.spark.deploy.history
1818

19-
import java.io.{FileInputStream, FileWriter, File}
20-
import java.net.URL
19+
import java.io.{IOException, FileInputStream, FileWriter, File}
20+
import java.net.{HttpURLConnection, URL}
21+
import javax.servlet.http.HttpServletResponse
2122

2223
import org.apache.commons.io.{FileUtils, IOUtils}
2324

@@ -72,7 +73,11 @@ class HistoryServerSuite extends FunSuite with BeforeAndAfter with Matchers {
7273
// resource folder
7374
cases.foreach{case(name, path) =>
7475
test(name){
75-
val json = getUrl(path)
76+
val (code, jsonOpt, errOpt) = getContentAndCode(path)
77+
code should be (HttpServletResponse.SC_OK)
78+
jsonOpt should be ('defined)
79+
errOpt should be (None)
80+
val json = jsonOpt.get
7681
val exp = IOUtils.toString(new FileInputStream(new File(expRoot, path + "/json_expectation")))
7782
json should be (exp)
7883
}
@@ -83,7 +88,42 @@ class HistoryServerSuite extends FunSuite with BeforeAndAfter with Matchers {
8388
}
8489

8590
test("response codes on bad paths") {
86-
pending
91+
val badAppId = getContentAndCode("applications/foobar")
92+
badAppId._1 should be (HttpServletResponse.SC_BAD_REQUEST)
93+
badAppId._3 should be (Some("unknown app: foobar"))
94+
95+
val badStageId = getContentAndCode("applications/local-1422981780767/stages/12345")
96+
badStageId._1 should be (HttpServletResponse.SC_BAD_REQUEST)
97+
badStageId._3 should be (Some("unknown stage: 12345"))
98+
99+
val badStageId2 = getContentAndCode("applications/local-1422981780767/stages/flimflam")
100+
badStageId2._1 should be (HttpServletResponse.SC_BAD_REQUEST)
101+
badStageId2._3 should be (Some("no valid stageId in path"))
102+
103+
104+
getContentAndCode("foobar")._1 should be (HttpServletResponse.SC_NOT_FOUND)
105+
106+
}
107+
108+
def getContentAndCode(path: String): (Int, Option[String], Option[String]) = {
109+
val url = new URL(s"http://localhost:$port/json/v1/$path")
110+
val connection = url.openConnection().asInstanceOf[HttpURLConnection]
111+
connection.setRequestMethod("GET")
112+
connection.connect()
113+
val code = connection.getResponseCode()
114+
val inString = try {
115+
val in = Option(connection.getInputStream())
116+
in.map{IOUtils.toString}
117+
} catch {
118+
case io: IOException => None
119+
}
120+
val errString = try {
121+
val err = Option(connection.getErrorStream())
122+
err.map{IOUtils.toString}
123+
} catch {
124+
case io: IOException => None
125+
}
126+
(code, inString, errString)
87127
}
88128

89129

0 commit comments

Comments
 (0)