19
19
20
20
package org .elasticsearch .http .nio ;
21
21
22
+ import io .netty .handler .codec .http .HttpMethod ;
22
23
import io .netty .handler .timeout .ReadTimeoutException ;
23
24
import org .apache .logging .log4j .Logger ;
24
25
import org .apache .logging .log4j .message .ParameterizedMessage ;
28
29
import org .elasticsearch .action .ActionFuture ;
29
30
import org .elasticsearch .action .ActionListener ;
30
31
import org .elasticsearch .action .support .PlainActionFuture ;
32
+ import org .elasticsearch .common .Strings ;
31
33
import org .elasticsearch .common .network .NetworkAddress ;
32
34
import org .elasticsearch .common .network .NetworkService ;
33
35
import org .elasticsearch .common .settings .Setting ;
38
40
import org .elasticsearch .common .util .BigArrays ;
39
41
import org .elasticsearch .common .util .concurrent .EsExecutors ;
40
42
import org .elasticsearch .common .xcontent .NamedXContentRegistry ;
43
+ import org .elasticsearch .http .AbstractHttpServerTransport ;
41
44
import org .elasticsearch .http .BindHttpException ;
42
45
import org .elasticsearch .http .HttpHandlingSettings ;
43
46
import org .elasticsearch .http .HttpServerTransport ;
44
47
import 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 ;
46
50
import org .elasticsearch .nio .AcceptingSelector ;
47
51
import org .elasticsearch .nio .AcceptorEventHandler ;
48
52
import org .elasticsearch .nio .BytesChannelContext ;
56
60
import org .elasticsearch .nio .SocketChannelContext ;
57
61
import org .elasticsearch .nio .SocketEventHandler ;
58
62
import org .elasticsearch .nio .SocketSelector ;
63
+ import org .elasticsearch .rest .RestUtils ;
59
64
import org .elasticsearch .threadpool .ThreadPool ;
60
65
61
66
import java .io .IOException ;
64
69
import java .nio .channels .ServerSocketChannel ;
65
70
import java .nio .channels .SocketChannel ;
66
71
import java .util .ArrayList ;
72
+ import java .util .Arrays ;
67
73
import java .util .Collections ;
68
74
import java .util .List ;
69
75
import java .util .Set ;
70
76
import java .util .concurrent .ConcurrentHashMap ;
71
77
import java .util .concurrent .atomic .AtomicReference ;
72
78
import java .util .function .Consumer ;
79
+ import java .util .regex .Pattern ;
73
80
74
81
import static org .elasticsearch .common .settings .Setting .intSetting ;
75
82
import 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 ;
76
89
import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_COMPRESSION ;
77
90
import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_COMPRESSION_LEVEL ;
78
91
import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_DETAILED_ERRORS_ENABLED ;
86
99
import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_TCP_REUSE_ADDRESS ;
87
100
import static org .elasticsearch .http .HttpTransportSettings .SETTING_HTTP_TCP_SEND_BUFFER_SIZE ;
88
101
import static org .elasticsearch .http .HttpTransportSettings .SETTING_PIPELINING_MAX_EVENTS ;
102
+ import static org .elasticsearch .http .nio .cors .NioCorsHandler .ANY_ORIGIN ;
89
103
90
104
public class NioHttpServerTransport extends AbstractHttpServerTransport {
91
105
@@ -115,6 +129,7 @@ public class NioHttpServerTransport extends AbstractHttpServerTransport {
115
129
private final Set <NioSocketChannel > socketChannels = Collections .newSetFromMap (new ConcurrentHashMap <>());
116
130
private NioGroup nioGroup ;
117
131
private HttpChannelFactory channelFactory ;
132
+ private final NioCorsConfig corsConfig ;
118
133
119
134
public NioHttpServerTransport (Settings settings , NetworkService networkService , BigArrays bigArrays , ThreadPool threadPool ,
120
135
NamedXContentRegistry xContentRegistry , HttpServerTransport .Dispatcher dispatcher ) {
@@ -136,6 +151,7 @@ public NioHttpServerTransport(Settings settings, NetworkService networkService,
136
151
SETTING_HTTP_COMPRESSION_LEVEL .get (settings ),
137
152
SETTING_HTTP_DETAILED_ERRORS_ENABLED .get (settings ),
138
153
pipeliningMaxEvents );
154
+ this .corsConfig = buildCorsConfig (settings );
139
155
140
156
this .tcpNoDelay = SETTING_HTTP_TCP_NO_DELAY .get (settings );
141
157
this .tcpKeepAlive = SETTING_HTTP_TCP_KEEP_ALIVE .get (settings );
@@ -279,6 +295,38 @@ protected void nonChannelExceptionCaught(Exception ex) {
279
295
logger .warn (new ParameterizedMessage ("exception caught on transport layer [thread={}]" , Thread .currentThread ().getName ()), ex );
280
296
}
281
297
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
+
282
330
private void closeChannels (List <NioChannel > channels ) {
283
331
List <ActionFuture <Void >> futures = new ArrayList <>(channels .size ());
284
332
@@ -315,7 +363,7 @@ private HttpChannelFactory() {
315
363
public NioSocketChannel createChannel (SocketSelector selector , SocketChannel channel ) throws IOException {
316
364
NioSocketChannel nioChannel = new NioSocketChannel (channel );
317
365
HttpReadWriteHandler httpReadWritePipeline = new HttpReadWriteHandler (nioChannel ,NioHttpServerTransport .this ,
318
- httpHandlingSettings , xContentRegistry , threadPool .getThreadContext ());
366
+ httpHandlingSettings , xContentRegistry , corsConfig , threadPool .getThreadContext ());
319
367
Consumer <Exception > exceptionHandler = (e ) -> exceptionCaught (nioChannel , e );
320
368
SocketChannelContext context = new BytesChannelContext (nioChannel , selector , exceptionHandler , httpReadWritePipeline ,
321
369
InboundChannelBuffer .allocatingInstance ());
0 commit comments