/** * Copyright 2011 Couchbase, Inc. * * 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 org.couchbase.mock.http; import com.google.gson.JsonElement; import com.sun.net.httpserver.HttpHandler; import org.apache.http.*; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpRequestHandler; import org.apache.http.util.EntityUtils; import org.couchbase.mock.*; import org.couchbase.mock.httpio.HandlerUtil; import org.couchbase.mock.httpio.HttpServer; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Handler; /** * @author Sergey Avseyev */ public class PoolsHandler { private final CouchbaseMock mock; public PoolsHandler(CouchbaseMock mock) { this.mock = mock; } private final HttpRequestHandler poolHandler = new HttpRequestHandler() { @Override public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { String payload = StateGrabber.getAllPoolsJSON(mock); HandlerUtil.makeJsonResponse(response, payload); } }; private final HttpRequestHandler poolsDefaultHandler = new HttpRequestHandler() { @Override public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { String payload = StateGrabber.getPoolInfoJSON(mock); HandlerUtil.makeJsonResponse(response, payload); } }; private final HttpRequestHandler sampleBucketsHandler = new HttpRequestHandler() { @Override public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { AuthContext authContext = HandlerUtil.getAuth(context, request); if (!mock.getAuthenticator().isAdministrator(authContext)) { response.setStatusCode(HttpStatus.SC_UNAUTHORIZED); return; } if (!request.getRequestLine().getMethod().equals("POST")) { HandlerUtil.makeResponse(response, "Not Found", HttpStatus.SC_NOT_FOUND); return; } // Parse the JSON if (! (request instanceof HttpEntityEnclosingRequest)) { HandlerUtil.make400Response(response, "Must have body"); return; } String rawBody = EntityUtils.toString(((HttpEntityEnclosingRequest) request).getEntity()); JsonElement elem = JsonUtils.GSON.fromJson(rawBody, JsonElement.class); if (!elem.isJsonArray()) { HandlerUtil.make400Response(response, "Request must be JSON array"); return; } for (JsonElement mem : elem.getAsJsonArray()) { if (!mem.isJsonPrimitive()) { HandlerUtil.make400Response(response, "Element must be string"); return; } String s = mem.getAsString(); if (!s.equals("beer-sample")) { HandlerUtil.make400Response(response, String.format("[\"Sample %s is not a valid sample.\"]", s)); return; } // Load the bucket! try { BucketConfiguration newConfig = new BucketConfiguration(mock.getDefaultConfig()); newConfig.name = "beer-sample"; try { mock.createBucket(newConfig); } catch (BucketAlreadyExistsException ex) { HandlerUtil.make400Response(response, "[\"Sample beer-sample is already loaded.\"]"); return; } DocumentLoader.loadBeerSample(mock); } catch (IOException ex) { HandlerUtil.makeResponse(response, ex.toString(), HttpStatus.SC_INTERNAL_SERVER_ERROR); } } } }; class CreateBucketBadParamsException extends Exception { CreateBucketBadParamsException(String message) { super(message); } } private final HttpRequestHandler allBucketsHandler = new HttpRequestHandler() { private void handleListBuckets(HttpRequest request, HttpResponse response, AuthContext authContext) throws HttpException, IOException{ List<Bucket> allowedBuckets = new ArrayList<Bucket>(mock.getBuckets().size()); Authenticator authenticator = mock.getAuthenticator(); for (Bucket bucket : mock.getBuckets().values()) { if (authenticator.isAuthorizedForBucket(authContext, bucket)) { allowedBuckets.add(bucket); } } String payload = StateGrabber.getAllBucketsJSON(allowedBuckets); HandlerUtil.makeJsonResponse(response, payload); } @Override public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { String methodName = request.getRequestLine().getMethod(); AuthContext authContext = HandlerUtil.getAuth(context, request); if (methodName.equals("GET")) { handleListBuckets(request, response, authContext); } else if (methodName.equals("POST")) { if (!mock.getAuthenticator().isAdministrator(authContext)) { response.setStatusCode(HttpStatus.SC_UNAUTHORIZED); } else { try { // Create new bucket handleCreateBucket(request, response, context); } catch (CreateBucketBadParamsException ex) { // The docs say 204, however when trying this out on my own, i get 500s all the time. ohwell HandlerUtil.makeResponse(response, ex.getMessage(), HttpStatus.SC_BAD_REQUEST); } } } } }; public void handleCreateBucket(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException, CreateBucketBadParamsException { HttpEntityEnclosingRequest entRequest; if (! (request instanceof HttpEntityEnclosingRequest)) { throw new CreateBucketBadParamsException("Must provide bucket parameters"); } BucketConfiguration config = new BucketConfiguration(mock.getDefaultConfig()); entRequest = (HttpEntityEnclosingRequest) request; Map<String,String> params = HandlerUtil.getQueryParams(EntityUtils.toString(entRequest.getEntity())); String name = params.get("name"); String authType = params.get("authType"); if (name == null || name.isEmpty()) { throw new CreateBucketBadParamsException("Must provide bucket name"); } config.name = name; if (authType == null || authType.isEmpty()) { throw new CreateBucketBadParamsException("authType must be specified"); } else if (authType.equals("none")) { HandlerUtil.makeResponse(response, "Non-SASL auth not supported", HttpStatus.SC_INTERNAL_SERVER_ERROR); return; } else if (authType.equals("sasl")) { // OK. but we handle this later config.password = params.get("saslPassword"); if (config.password == null) { config.password = ""; } } else { throw new CreateBucketBadParamsException( "authType must be 'sasl' or 'none' (note 'none' is not supported, but is valid)"); } try { String sReplicas = params.get("replicaNumber"); if (sReplicas != null) { config.numReplicas = Integer.parseInt(sReplicas); if (config.numReplicas > config.numNodes-1) { throw new CreateBucketBadParamsException("Not enough nodes for replicas"); } } String sQuota = params.get("ramQuotaMB"); if (sQuota == null) { throw new CreateBucketBadParamsException("ramQuotaMB missing (but we ignore it)"); } int iQuota = Integer.parseInt(sQuota); if (iQuota < 100) { throw new CreateBucketBadParamsException("Ram quota must be greater than 100"); } } catch (NumberFormatException ex) { throw new CreateBucketBadParamsException("Bad numeric value"); } try { mock.createBucket(config); response.setStatusCode(HttpStatus.SC_ACCEPTED); } catch (BucketAlreadyExistsException ex) { HandlerUtil.makeResponse(response, ex.getMessage(), HttpStatus.SC_INTERNAL_SERVER_ERROR); } } public void handleDeleteBucket(HttpRequest request, HttpResponse response, HttpContext context, Bucket bucket) throws HttpException, IOException { AuthContext authContext = HandlerUtil.getAuth(context, request); Authenticator authenticator = mock.getAuthenticator(); if (!authenticator.isAdministrator(authContext)) { response.setStatusCode(HttpStatus.SC_UNAUTHORIZED); return; } try { mock.removeBucket(bucket.getName()); } catch (FileNotFoundException ex) { response.setStatusCode(HttpStatus.SC_NOT_FOUND); } } public void register(HttpServer server) { server.register("/pools", poolHandler); server.register(String.format("/pools/%s", mock.getPoolName()), poolsDefaultHandler); server.register(String.format("/pools/%s/buckets", mock.getPoolName()), allBucketsHandler); server.register("/sampleBuckets/install", sampleBucketsHandler); } }