1919
2020package org .elasticsearch .http .nio ;
2121
22+ import io .netty .handler .codec .http .HttpMethod ;
2223import io .netty .handler .timeout .ReadTimeoutException ;
2324import org .apache .logging .log4j .Logger ;
2425import org .apache .logging .log4j .message .ParameterizedMessage ;
2829import org .elasticsearch .action .ActionFuture ;
2930import org .elasticsearch .action .ActionListener ;
3031import org .elasticsearch .action .support .PlainActionFuture ;
32+ import org .elasticsearch .common .Strings ;
3133import org .elasticsearch .common .network .NetworkAddress ;
3234import org .elasticsearch .common .network .NetworkService ;
3335import org .elasticsearch .common .settings .Setting ;
3840import org .elasticsearch .common .util .BigArrays ;
3941import org .elasticsearch .common .util .concurrent .EsExecutors ;
4042import org .elasticsearch .common .xcontent .NamedXContentRegistry ;
43+ import org .elasticsearch .http .AbstractHttpServerTransport ;
4144import org .elasticsearch .http .BindHttpException ;
4245import org .elasticsearch .http .HttpHandlingSettings ;
4346import org .elasticsearch .http .HttpServerTransport ;
4447import org .elasticsearch .http .HttpStats ;
45- import org .elasticsearch .http .AbstractHttpServerTransport ;
48+ import org .elasticsearch .http .nio .cors .NioCorsConfig ;
49+ import org .elasticsearch .http .nio .cors .NioCorsConfigBuilder ;
4650import org .elasticsearch .nio .AcceptingSelector ;
4751import org .elasticsearch .nio .AcceptorEventHandler ;
4852import org .elasticsearch .nio .BytesChannelContext ;
5660import org .elasticsearch .nio .SocketChannelContext ;
5761import org .elasticsearch .nio .SocketEventHandler ;
5862import org .elasticsearch .nio .SocketSelector ;
63+ import org .elasticsearch .rest .RestUtils ;
5964import org .elasticsearch .threadpool .ThreadPool ;
6065
6166import java .io .IOException ;
6469import java .nio .channels .ServerSocketChannel ;
6570import java .nio .channels .SocketChannel ;
6671import java .util .ArrayList ;
72+ import java .util .Arrays ;
6773import java .util .Collections ;
6874import java .util .List ;
6975import java .util .Set ;
7076import java .util .concurrent .ConcurrentHashMap ;
7177import java .util .concurrent .atomic .AtomicReference ;
7278import java .util .function .Consumer ;
79+ import java .util .regex .Pattern ;
7380
7481import static org .elasticsearch .common .settings .Setting .intSetting ;
7582import static org .elasticsearch .common .util .concurrent .EsExecutors .daemonThreadFactory ;
83+ import static org .elasticsearch .http .HttpTransportSettings .SETTING_CORS_ALLOW_CREDENTIALS ;
84+ import static org .elasticsearch .http .HttpTransportSettings .SETTING_CORS_ALLOW_HEADERS ;
85+ import static org .elasticsearch .http .HttpTransportSettings .SETTING_CORS_ALLOW_METHODS ;
86+ import static org .elasticsearch .http .HttpTransportSettings .SETTING_CORS_ALLOW_ORIGIN ;
87+ import static org .elasticsearch .http .HttpTransportSettings .SETTING_CORS_ENABLED ;
88+ import static org .elasticsearch .http .HttpTransportSettings .SETTING_CORS_MAX_AGE ;
7689import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_COMPRESSION ;
7790import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_COMPRESSION_LEVEL ;
7891import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_DETAILED_ERRORS_ENABLED ;
8699import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_TCP_REUSE_ADDRESS ;
87100import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_TCP_SEND_BUFFER_SIZE ;
88101import static org .elasticsearch .http .HttpTransportSettings .SETTING_PIPELINING_MAX_EVENTS ;
102+ import static org .elasticsearch .http .nio .cors .NioCorsHandler .ANY_ORIGIN ;
89103
90104public class NioHttpServerTransport extends AbstractHttpServerTransport {
91105
@@ -115,6 +129,7 @@ public class NioHttpServerTransport extends AbstractHttpServerTransport {
115129 private final Set <NioSocketChannel > socketChannels = Collections .newSetFromMap (new ConcurrentHashMap <>());
116130 private NioGroup nioGroup ;
117131 private HttpChannelFactory channelFactory ;
132+ private final NioCorsConfig corsConfig ;
118133
119134 public NioHttpServerTransport (Settings settings , NetworkService networkService , BigArrays bigArrays , ThreadPool threadPool ,
120135 NamedXContentRegistry xContentRegistry , HttpServerTransport .Dispatcher dispatcher ) {
@@ -136,6 +151,7 @@ public NioHttpServerTransport(Settings settings, NetworkService networkService,
136151 SETTING_HTTP_COMPRESSION_LEVEL .get (settings ),
137152 SETTING_HTTP_DETAILED_ERRORS_ENABLED .get (settings ),
138153 pipeliningMaxEvents );
154+ this .corsConfig = buildCorsConfig (settings );
139155
140156 this .tcpNoDelay = SETTING_HTTP_TCP_NO_DELAY .get (settings );
141157 this .tcpKeepAlive = SETTING_HTTP_TCP_KEEP_ALIVE .get (settings );
@@ -279,6 +295,38 @@ protected void nonChannelExceptionCaught(Exception ex) {
279295 logger .warn (new ParameterizedMessage ("exception caught on transport layer [thread={}]" , Thread .currentThread ().getName ()), ex );
280296 }
281297
298+ static NioCorsConfig buildCorsConfig (Settings settings ) {
299+ if (SETTING_CORS_ENABLED .get (settings ) == false ) {
300+ return NioCorsConfigBuilder .forOrigins ().disable ().build ();
301+ }
302+ String origin = SETTING_CORS_ALLOW_ORIGIN .get (settings );
303+ final NioCorsConfigBuilder builder ;
304+ if (Strings .isNullOrEmpty (origin )) {
305+ builder = NioCorsConfigBuilder .forOrigins ();
306+ } else if (origin .equals (ANY_ORIGIN )) {
307+ builder = NioCorsConfigBuilder .forAnyOrigin ();
308+ } else {
309+ Pattern p = RestUtils .checkCorsSettingForRegex (origin );
310+ if (p == null ) {
311+ builder = NioCorsConfigBuilder .forOrigins (RestUtils .corsSettingAsArray (origin ));
312+ } else {
313+ builder = NioCorsConfigBuilder .forPattern (p );
314+ }
315+ }
316+ if (SETTING_CORS_ALLOW_CREDENTIALS .get (settings )) {
317+ builder .allowCredentials ();
318+ }
319+ String [] strMethods = Strings .tokenizeToStringArray (SETTING_CORS_ALLOW_METHODS .get (settings ), "," );
320+ HttpMethod [] methods = Arrays .stream (strMethods )
321+ .map (HttpMethod ::valueOf )
322+ .toArray (HttpMethod []::new );
323+ return builder .allowedRequestMethods (methods )
324+ .maxAge (SETTING_CORS_MAX_AGE .get (settings ))
325+ .allowedRequestHeaders (Strings .tokenizeToStringArray (SETTING_CORS_ALLOW_HEADERS .get (settings ), "," ))
326+ .shortCircuit ()
327+ .build ();
328+ }
329+
282330 private void closeChannels (List <NioChannel > channels ) {
283331 List <ActionFuture <Void >> futures = new ArrayList <>(channels .size ());
284332
@@ -315,7 +363,7 @@ private HttpChannelFactory() {
315363 public NioSocketChannel createChannel (SocketSelector selector , SocketChannel channel ) throws IOException {
316364 NioSocketChannel nioChannel = new NioSocketChannel (channel );
317365 HttpReadWriteHandler httpReadWritePipeline = new HttpReadWriteHandler (nioChannel ,NioHttpServerTransport .this ,
318- httpHandlingSettings , xContentRegistry , threadPool .getThreadContext ());
366+ httpHandlingSettings , xContentRegistry , corsConfig , threadPool .getThreadContext ());
319367 Consumer <Exception > exceptionHandler = (e ) -> exceptionCaught (nioChannel , e );
320368 SocketChannelContext context = new BytesChannelContext (nioChannel , selector , exceptionHandler , httpReadWritePipeline ,
321369 InboundChannelBuffer .allocatingInstance ());
0 commit comments