/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.presto.raptor.backup; import io.airlift.node.NodeInfo; import io.airlift.slice.Slices; import io.airlift.slice.XxHash64; import javax.annotation.concurrent.GuardedBy; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HEAD; import javax.ws.rs.HeaderParam; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; import static com.facebook.presto.raptor.backup.HttpBackupStore.CONTENT_XXH64; import static com.facebook.presto.raptor.backup.HttpBackupStore.PRESTO_ENVIRONMENT; import static java.lang.Long.parseUnsignedLong; import static java.util.Objects.requireNonNull; import static javax.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.FORBIDDEN; import static javax.ws.rs.core.Response.Status.GONE; import static javax.ws.rs.core.Response.Status.NOT_FOUND; @Path("/") public class TestingHttpBackupResource { private final String environment; @GuardedBy("this") private final Map<UUID, byte[]> shards = new HashMap<>(); @Inject public TestingHttpBackupResource(NodeInfo nodeInfo) { this(nodeInfo.getEnvironment()); } public TestingHttpBackupResource(String environment) { this.environment = requireNonNull(environment, "environment is null"); } @HEAD @Path("{uuid}") public synchronized Response headRequest( @HeaderParam(PRESTO_ENVIRONMENT) String environment, @PathParam("uuid") UUID uuid) { checkEnvironment(environment); if (!shards.containsKey(uuid)) { return Response.status(NOT_FOUND).build(); } if (shards.get(uuid) == null) { return Response.status(GONE).build(); } return Response.noContent().build(); } @GET @Path("{uuid}") @Produces(APPLICATION_OCTET_STREAM) public synchronized Response getRequest( @HeaderParam(PRESTO_ENVIRONMENT) String environment, @PathParam("uuid") UUID uuid) { checkEnvironment(environment); if (!shards.containsKey(uuid)) { return Response.status(NOT_FOUND).build(); } byte[] bytes = shards.get(uuid); if (bytes == null) { return Response.status(GONE).build(); } return Response.ok(bytes).build(); } @PUT @Path("{uuid}") public synchronized Response putRequest( @HeaderParam(PRESTO_ENVIRONMENT) String environment, @HeaderParam(CONTENT_XXH64) String hexHash, @Context HttpServletRequest request, @PathParam("uuid") UUID uuid, byte[] bytes) { checkEnvironment(environment); if ((request.getContentLength() < 0) || (bytes.length != request.getContentLength())) { return Response.status(BAD_REQUEST).build(); } if (parseUnsignedLong(hexHash, 16) != XxHash64.hash(Slices.wrappedBuffer(bytes))) { return Response.status(BAD_REQUEST).build(); } if (shards.containsKey(uuid)) { byte[] existing = shards.get(uuid); if ((existing == null) || !Arrays.equals(bytes, existing)) { return Response.status(FORBIDDEN).build(); } } shards.put(uuid, bytes); return Response.noContent().build(); } @DELETE @Path("{uuid}") public synchronized Response deleteRequest( @HeaderParam(PRESTO_ENVIRONMENT) String environment, @PathParam("uuid") UUID uuid) { checkEnvironment(environment); if (!shards.containsKey(uuid)) { return Response.status(NOT_FOUND).build(); } if (shards.get(uuid) == null) { return Response.status(GONE).build(); } shards.put(uuid, null); return Response.noContent().build(); } private void checkEnvironment(String environment) { if (!this.environment.equals(environment)) { throw new WebApplicationException(Response.status(FORBIDDEN).build()); } } }