5353import java .util .concurrent .atomic .AtomicBoolean ;
5454import java .util .function .UnaryOperator ;
5555
56+ import static org .elasticsearch .rest .BytesRestResponse .TEXT_CONTENT_TYPE ;
5657import static org .elasticsearch .rest .RestStatus .BAD_REQUEST ;
57- import static org .elasticsearch .rest .RestStatus .METHOD_NOT_ALLOWED ;
58- import static org .elasticsearch .rest .RestStatus .FORBIDDEN ;
5958import static org .elasticsearch .rest .RestStatus .INTERNAL_SERVER_ERROR ;
59+ import static org .elasticsearch .rest .RestStatus .METHOD_NOT_ALLOWED ;
6060import static org .elasticsearch .rest .RestStatus .NOT_ACCEPTABLE ;
6161import static org .elasticsearch .rest .RestStatus .OK ;
62- import static org .elasticsearch .rest .BytesRestResponse .TEXT_CONTENT_TYPE ;
6362
6463public class RestController implements HttpServerTransport .Dispatcher {
6564
@@ -253,7 +252,7 @@ boolean dispatchRequest(final RestRequest request, final RestChannel channel, fi
253252 // If an alternative handler for an explicit path is registered to a
254253 // different HTTP method than the one supplied - return a 405 Method
255254 // Not Allowed error.
256- handleUnsupportedHttpMethod (request , channel , validMethodSet );
255+ handleUnsupportedHttpMethod (request , channel , validMethodSet , null );
257256 requestHandled = true ;
258257 } else if (validMethodSet .contains (request .method ()) == false
259258 && (request .method () == RestRequest .Method .OPTIONS )) {
@@ -330,16 +329,28 @@ void tryAllHandlers(final RestRequest request, final RestChannel channel, final
330329 return ;
331330 }
332331
333- // Loop through all possible handlers, attempting to dispatch the request
334- Iterator <MethodHandlers > allHandlers = getAllHandlers (request );
335- for (Iterator <MethodHandlers > it = allHandlers ; it .hasNext (); ) {
336- final Optional <RestHandler > mHandler = Optional .ofNullable (it .next ()).flatMap (mh -> mh .getHandler (request .method ()));
337- requestHandled = dispatchRequest (request , channel , client , mHandler );
338- if (requestHandled ) {
339- break ;
332+ try {
333+ // Resolves the HTTP method and fails if the method is invalid
334+ final RestRequest .Method requestMethod = request .method ();
335+
336+ // Loop through all possible handlers, attempting to dispatch the request
337+ Iterator <MethodHandlers > allHandlers = getAllHandlers (request );
338+ for (Iterator <MethodHandlers > it = allHandlers ; it .hasNext (); ) {
339+ Optional <RestHandler > mHandler = Optional .empty ();
340+ if (requestMethod != null ) {
341+ mHandler = Optional .ofNullable (it .next ()).flatMap (mh -> mh .getHandler (requestMethod ));
342+ }
343+ requestHandled = dispatchRequest (request , channel , client , mHandler );
344+ if (requestHandled ) {
345+ break ;
346+ }
340347 }
348+ } catch (final IllegalArgumentException e ) {
349+ handleUnsupportedHttpMethod (request , channel , getValidHandlerMethodSet (request ), e );
350+ requestHandled = true ;
341351 }
342352
353+
343354 // If request has not been handled, fallback to a bad request error.
344355 if (requestHandled == false ) {
345356 handleBadRequest (request , channel );
@@ -365,11 +376,25 @@ Iterator<MethodHandlers> getAllHandlers(final RestRequest request) {
365376 * <a href="https://tools.ietf.org/html/rfc2616#section-10.4.6">HTTP/1.1 -
366377 * 10.4.6 - 405 Method Not Allowed</a>).
367378 */
368- private void handleUnsupportedHttpMethod (RestRequest request , RestChannel channel , Set <RestRequest .Method > validMethodSet ) {
379+ private void handleUnsupportedHttpMethod (final RestRequest request ,
380+ final RestChannel channel ,
381+ final Set <RestRequest .Method > validMethodSet ,
382+ @ Nullable final IllegalArgumentException exception ) {
369383 try {
370- BytesRestResponse bytesRestResponse = BytesRestResponse .createSimpleErrorResponse (channel , METHOD_NOT_ALLOWED ,
371- "Incorrect HTTP method for uri [" + request .uri () + "] and method [" + request .method () + "], allowed: " + validMethodSet );
372- bytesRestResponse .addHeader ("Allow" , Strings .collectionToDelimitedString (validMethodSet , "," ));
384+ final StringBuilder msg = new StringBuilder ();
385+ if (exception != null ) {
386+ msg .append (exception .getMessage ());
387+ } else {
388+ msg .append ("Incorrect HTTP method for uri [" ).append (request .uri ());
389+ msg .append ("] and method [" ).append (request .method ()).append ("]" );
390+ }
391+ if (validMethodSet .isEmpty () == false ) {
392+ msg .append (", allowed: " ).append (validMethodSet );
393+ }
394+ BytesRestResponse bytesRestResponse = BytesRestResponse .createSimpleErrorResponse (channel , METHOD_NOT_ALLOWED , msg .toString ());
395+ if (validMethodSet .isEmpty () == false ) {
396+ bytesRestResponse .addHeader ("Allow" , Strings .collectionToDelimitedString (validMethodSet , "," ));
397+ }
373398 channel .sendResponse (bytesRestResponse );
374399 } catch (final IOException e ) {
375400 logger .warn ("failed to send bad request response" , e );
@@ -385,11 +410,12 @@ private void handleUnsupportedHttpMethod(RestRequest request, RestChannel channe
385410 * - Options</a>).
386411 */
387412 private void handleOptionsRequest (RestRequest request , RestChannel channel , Set <RestRequest .Method > validMethodSet ) {
388- if (request .method () == RestRequest .Method .OPTIONS && validMethodSet .size () > 0 ) {
413+ assert request .method () == RestRequest .Method .OPTIONS ;
414+ if (validMethodSet .isEmpty () == false ) {
389415 BytesRestResponse bytesRestResponse = new BytesRestResponse (OK , TEXT_CONTENT_TYPE , BytesArray .EMPTY );
390416 bytesRestResponse .addHeader ("Allow" , Strings .collectionToDelimitedString (validMethodSet , "," ));
391417 channel .sendResponse (bytesRestResponse );
392- } else if ( request . method () == RestRequest . Method . OPTIONS && validMethodSet . size () == 0 ) {
418+ } else {
393419 /*
394420 * When we have an OPTIONS HTTP request and no valid handlers,
395421 * simply send OK by default (with the Access Control Origin header
@@ -433,20 +459,25 @@ private String getPath(RestRequest request) {
433459 return request .rawPath ();
434460 }
435461
436- void handleFavicon (RestRequest request , RestChannel channel ) {
437- if (request .method () == RestRequest .Method .GET ) {
438- try {
439- try (InputStream stream = getClass ().getResourceAsStream ("/config/favicon.ico" )) {
440- ByteArrayOutputStream out = new ByteArrayOutputStream ();
441- Streams .copy (stream , out );
442- BytesRestResponse restResponse = new BytesRestResponse (RestStatus .OK , "image/x-icon" , out .toByteArray ());
443- channel .sendResponse (restResponse );
462+ private void handleFavicon (final RestRequest request , final RestChannel channel ) {
463+ try {
464+ if (request .method () != RestRequest .Method .GET ) {
465+ handleUnsupportedHttpMethod (request , channel , Set .of (RestRequest .Method .GET ), null );
466+ } else {
467+ try {
468+ try (InputStream stream = getClass ().getResourceAsStream ("/config/favicon.ico" )) {
469+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
470+ Streams .copy (stream , out );
471+ BytesRestResponse restResponse = new BytesRestResponse (RestStatus .OK , "image/x-icon" , out .toByteArray ());
472+ channel .sendResponse (restResponse );
473+ }
474+ } catch (IOException e ) {
475+ channel .sendResponse (
476+ new BytesRestResponse (INTERNAL_SERVER_ERROR , BytesRestResponse .TEXT_CONTENT_TYPE , BytesArray .EMPTY ));
444477 }
445- } catch (IOException e ) {
446- channel .sendResponse (new BytesRestResponse (INTERNAL_SERVER_ERROR , BytesRestResponse .TEXT_CONTENT_TYPE , BytesArray .EMPTY ));
447478 }
448- } else {
449- channel . sendResponse ( new BytesRestResponse ( FORBIDDEN , BytesRestResponse . TEXT_CONTENT_TYPE , BytesArray . EMPTY ) );
479+ } catch ( final IllegalArgumentException e ) {
480+ handleUnsupportedHttpMethod ( request , channel , Set . of ( RestRequest . Method . GET ), e );
450481 }
451482 }
452483
@@ -512,5 +543,4 @@ private static CircuitBreaker inFlightRequestsBreaker(CircuitBreakerService circ
512543 // We always obtain a fresh breaker to reflect changes to the breaker configuration.
513544 return circuitBreakerService .getBreaker (CircuitBreaker .IN_FLIGHT_REQUESTS );
514545 }
515-
516546}
0 commit comments