/* * Copyright 2016 LINE Corporation * * LINE Corporation licenses this file to you 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.linecorp.armeria.server.http; import com.linecorp.armeria.common.SerializationFormat; import com.linecorp.armeria.common.http.DefaultHttpResponse; import com.linecorp.armeria.common.http.HttpMethod; import com.linecorp.armeria.common.http.HttpRequest; import com.linecorp.armeria.common.http.HttpResponse; import com.linecorp.armeria.common.http.HttpResponseWriter; import com.linecorp.armeria.common.http.HttpStatus; import com.linecorp.armeria.common.logging.RequestLogBuilder; import com.linecorp.armeria.server.ServiceRequestContext; /** * A skeletal {@link HttpService} for easier HTTP service implementation. * * <p>This class provides the methods that handles the HTTP requests of the methods their names signify. * For example, {@link #doGet(ServiceRequestContext, HttpRequest, HttpResponseWriter) doGet()} method handles a * {@code GET} request. * <ul> * <li>{@link #doOptions(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * <li>{@link #doGet(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * <li>{@link #doHead(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * <li>{@link #doPost(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * <li>{@link #doPut(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * <li>{@link #doPatch(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * <li>{@link #doDelete(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * <li>{@link #doTrace(ServiceRequestContext, HttpRequest, HttpResponseWriter)}</li> * </ul> * These methods reject requests with a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response * by default. Override one of them to handle requests properly. */ public abstract class AbstractHttpService implements HttpService { /** * Serves the specified {@link HttpRequest} by delegating it to the matching {@code 'doMETHOD()'} method. * Override this method to perform an action for the requests of any HTTP methods: * <pre><code> * public class MyHttpService extends AbstractHttpService { * private final Map<HttpMethod, AtomicInteger> handledRequests = new ConcurrentHashMap<>(); * * @Override * public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception { * final HttpResponse res = super.serve(ctx, req); * handledRequests.computeIfAbsent( * req.method(), method -> new AtomicInteger()).incrementAndGet(); * return res; * } * } * </code></pre> */ @Override public HttpResponse serve(ServiceRequestContext ctx, HttpRequest req) throws Exception { try { final DefaultHttpResponse res = new DefaultHttpResponse(); switch (req.method()) { case OPTIONS: doOptions(ctx, req, res); break; case GET: doGet(ctx, req, res); break; case HEAD: doHead(ctx, req, res); break; case POST: doPost(ctx, req, res); break; case PUT: doPut(ctx, req, res); break; case PATCH: doPatch(ctx, req, res); break; case DELETE: doDelete(ctx, req, res); break; case TRACE: doTrace(ctx, req, res); break; default: res.respond(HttpStatus.METHOD_NOT_ALLOWED); } return res; } finally { final RequestLogBuilder logBuilder = ctx.logBuilder(); if (!logBuilder.isRequestContentDeferred()) { // Set the requestContent to null by default. // An implementation can override this behavior by setting the requestContent in do*() // implementation or by calling deferRequestContent(). logBuilder.requestContent(null, null); } // do*() methods are expected to set the serialization format before returning. logBuilder.serializationFormat(SerializationFormat.NONE); } } /** * Handles an {@link HttpMethod#OPTIONS OPTIONS} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doOptions(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } /** * Handles a {@link HttpMethod#GET GET} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doGet(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } /** * Handles a {@link HttpMethod#HEAD HEAD} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doHead(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } /** * Handles a {@link HttpMethod#POST POST} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doPost(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } /** * Handles a {@link HttpMethod#PUT PUT} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doPut(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } /** * Handles a {@link HttpMethod#PATCH PATCH} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doPatch(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } /** * Handles a {@link HttpMethod#DELETE DELETE} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doDelete(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } /** * Handles a {@link HttpMethod#TRACE TRACE} request. * This method sends a {@link HttpStatus#METHOD_NOT_ALLOWED 405 Method Not Allowed} response by default. */ protected void doTrace(ServiceRequestContext ctx, HttpRequest req, HttpResponseWriter res) throws Exception { res.respond(HttpStatus.METHOD_NOT_ALLOWED); } }