| 196 | |
| 197 | |
| 198 | Future<Response> Master::Http::api( |
| 199 | const Request& request, |
| 200 | const Option<Principal>& principal) const |
| 201 | { |
| 202 | // TODO(greggomann): Remove this check once the `Principal` type is used in |
| 203 | // `ReservationInfo`, `DiskInfo`, and within the master's `principals` map. |
| 204 | // See MESOS-7202. |
| 205 | if (principal.isSome() && principal->value.isNone()) { |
| 206 | return Forbidden( |
| 207 | "The request's authenticated principal contains claims, but no value " |
| 208 | "string. The master currently requires that principals have a value"); |
| 209 | } |
| 210 | |
| 211 | // TODO(vinod): Add metrics for rejected requests. |
| 212 | |
| 213 | // TODO(vinod): Add support for rate limiting. |
| 214 | |
| 215 | // When current master is not the leader, redirect to the leading master. |
| 216 | // Note that this could happen when an operator, or some other |
| 217 | // service, including a scheduler realizes this is the leading |
| 218 | // master before the master itself realizes it, e.g., due to a |
| 219 | // ZooKeeper watch delay. |
| 220 | if (!master->elected()) { |
| 221 | return redirect(request); |
| 222 | } |
| 223 | |
| 224 | CHECK_SOME(master->recovered); |
| 225 | |
| 226 | if (!master->recovered->isReady()) { |
| 227 | return ServiceUnavailable("Master has not finished recovery"); |
| 228 | } |
| 229 | |
| 230 | if (request.method != "POST") { |
| 231 | return MethodNotAllowed({"POST"}, request.method); |
| 232 | } |
| 233 | |
| 234 | v1::master::Call v1Call; |
| 235 | |
| 236 | // TODO(anand): Content type values are case-insensitive. |
| 237 | Option<string> contentType = request.headers.get("Content-Type"); |
| 238 | |
| 239 | if (contentType.isNone()) { |
| 240 | return BadRequest("Expecting 'Content-Type' to be present"); |
| 241 | } |
| 242 | |
| 243 | if (contentType.get() == APPLICATION_PROTOBUF) { |
| 244 | if (!v1Call.ParseFromString(request.body)) { |
| 245 | return BadRequest("Failed to parse body into Call protobuf"); |
| 246 | } |
| 247 | } else if (contentType.get() == APPLICATION_JSON) { |
| 248 | Try<JSON::Value> value = JSON::parse(request.body); |
| 249 | |
| 250 | if (value.isError()) { |
| 251 | return BadRequest("Failed to parse body into JSON: " + value.error()); |
| 252 | } |
| 253 | |
| 254 | Try<v1::master::Call> parse = |
| 255 | ::protobuf::parse<v1::master::Call>(value.get()); |
no test coverage detected