82
82
import org .eclipse .jetty .security .ConstraintMapping ;
83
83
import org .eclipse .jetty .security .ConstraintSecurityHandler ;
84
84
import org .eclipse .jetty .security .LoginService ;
85
- import org .eclipse .jetty .server .Connector ;
86
85
import org .eclipse .jetty .server .Handler ;
87
86
import org .eclipse .jetty .server .HttpConfiguration ;
88
87
import org .eclipse .jetty .server .HttpConnectionFactory ;
89
88
import org .eclipse .jetty .server .LowResourceMonitor ;
89
+ import org .eclipse .jetty .server .Request ;
90
90
import org .eclipse .jetty .server .Server ;
91
+ import org .eclipse .jetty .server .handler .AbstractHandler ;
91
92
import org .eclipse .jetty .server .handler .ContextHandler .Context ;
92
93
import org .eclipse .jetty .server .handler .ContextHandlerCollection ;
93
94
import org .eclipse .jetty .server .ServerConnector ;
95
+ import org .eclipse .jetty .server .handler .HandlerCollection ;
94
96
import org .eclipse .jetty .servlet .DefaultServlet ;
95
97
import org .eclipse .jetty .servlet .FilterHolder ;
96
98
import org .eclipse .jetty .servlet .FilterMapping ;
@@ -138,6 +140,8 @@ public class HttpServer {
138
140
private String appDir ;
139
141
private WebAppContext webAppContext ;
140
142
private Server webServer ;
143
+ private QueuedThreadPool threadPool ;
144
+ private PortHandlerWrapper portHandlerWrapper ;
141
145
142
146
/**
143
147
* Create a status server on the given port.
@@ -179,6 +183,7 @@ public static class Builder {
179
183
new LinkedList <Pair <String , Class <? extends HttpServlet >>>();
180
184
private boolean disableDirListing = false ;
181
185
private final Map <String , Pair <String , Filter >> globalFilters = new LinkedHashMap <>();
186
+ private String contextPath ;
182
187
183
188
public Builder (String name ) {
184
189
Preconditions .checkArgument (name != null && !name .isEmpty (), "Name must be specified" );
@@ -189,6 +194,10 @@ public HttpServer build() throws IOException {
189
194
return new HttpServer (this );
190
195
}
191
196
197
+ public void setContextPath (String contextPath ) {
198
+ this .contextPath = contextPath ;
199
+ }
200
+
192
201
public Builder setConf (HiveConf origConf ) {
193
202
this .conf = new HiveConf (origConf );
194
203
origConf .stripHiddenConfigurations (conf );
@@ -489,13 +498,13 @@ static boolean userHasAdministratorAccess(ServletContext servletContext,
489
498
/**
490
499
* Create the web context for the application of specified name
491
500
*/
492
- WebAppContext createWebAppContext (Builder b ) {
501
+ WebAppContext createWebAppContext (Builder b ) throws FileNotFoundException {
493
502
WebAppContext ctx = new WebAppContext ();
494
503
setContextAttributes (ctx .getServletContext (), b .contextAttrs );
495
504
ctx .getServletContext ().getSessionCookieConfig ().setHttpOnly (true );
496
505
ctx .setDisplayName (b .name );
497
- ctx .setContextPath ("/" );
498
- ctx .setWar (appDir + "/" + b .name );
506
+ ctx .setContextPath (b . contextPath == null ? "/" : b . contextPath );
507
+ ctx .setWar (getWebAppsPath ( b . name ) + "/" + b .name );
499
508
return ctx ;
500
509
}
501
510
@@ -519,8 +528,9 @@ void setupSpnegoFilter(Builder b, ServletContextHandler ctx) throws IOException
519
528
/**
520
529
* Setup cross-origin requests (CORS) filter.
521
530
* @param b - builder
531
+ * @param webAppContext - webAppContext
522
532
*/
523
- private void setupCORSFilter (Builder b ) {
533
+ private void setupCORSFilter (Builder b , WebAppContext webAppContext ) {
524
534
FilterHolder holder = new FilterHolder ();
525
535
holder .setClassName (CrossOriginFilter .class .getName ());
526
536
Map <String , String > params = new HashMap <>();
@@ -533,10 +543,62 @@ private void setupCORSFilter(Builder b) {
533
543
handler .addFilterWithMapping (holder , "/*" , FilterMapping .ALL );
534
544
}
535
545
546
+ public void addWebApp (Builder b ) throws IOException {
547
+ WebAppContext webAppContext = createWebAppContext (b );
548
+ ContextHandlerCollection portHandler = new ContextHandlerCollection ();
549
+ ServerConnector connector = addWebApp (b , webAppContext , portHandler );
550
+ portHandlerWrapper .addHandler (connector , portHandler );
551
+ }
552
+
553
+ private ServerConnector addWebApp (Builder b , WebAppContext webAppContext , ContextHandlerCollection portHandler )
554
+ throws IOException {
555
+
556
+ if (b .useSPNEGO ) {
557
+ // Secure the web server with kerberos
558
+ setupSpnegoFilter (b , webAppContext );
559
+ }
560
+
561
+ if (b .enableCORS ) {
562
+ setupCORSFilter (b , webAppContext );
563
+ }
564
+
565
+ Map <String , String > xFrameParams = setHeaders ();
566
+ if (b .xFrameEnabled ) {
567
+ setupXframeFilter (b , xFrameParams , webAppContext );
568
+ }
569
+
570
+ if (b .disableDirListing ) {
571
+ disableDirectoryListingOnServlet (webAppContext );
572
+ }
573
+
574
+ ServerConnector connector = createChannelConnector (threadPool .getQueueSize (), b );
575
+ webServer .addConnector (connector );
576
+
577
+ RewriteHandler rwHandler = new RewriteHandler ();
578
+ rwHandler .setRewriteRequestURI (true );
579
+ rwHandler .setRewritePathInfo (false );
580
+
581
+ RewriteRegexRule rootRule = new RewriteRegexRule ();
582
+ rootRule .setRegex ("^/$" );
583
+ rootRule .setReplacement (b .contextRootRewriteTarget );
584
+ rootRule .setTerminating (true );
585
+
586
+ rwHandler .addRule (rootRule );
587
+ rwHandler .setHandler (webAppContext );
588
+
589
+ portHandler .addHandler (rwHandler );
590
+
591
+ for (Pair <String , Class <? extends HttpServlet >> p : b .servlets ) {
592
+ addServlet (p .getFirst (), "/" + p .getFirst (), p .getSecond (), webAppContext );
593
+ }
594
+
595
+ return connector ;
596
+ }
597
+
536
598
/**
537
599
* Create a channel connector for "http/https" requests
538
600
*/
539
- Connector createChannelConnector (int queueSize , Builder b ) {
601
+ ServerConnector createChannelConnector (int queueSize , Builder b ) {
540
602
ServerConnector connector ;
541
603
542
604
final HttpConfiguration conf = new HttpConfiguration ();
@@ -604,7 +666,7 @@ void setContextAttributes(Context ctx, Map<String, Object> contextAttrs) {
604
666
605
667
private void createWebServer (final Builder b ) throws IOException {
606
668
// Create the thread pool for the web server to handle HTTP requests
607
- QueuedThreadPool threadPool = new QueuedThreadPool ();
669
+ threadPool = new QueuedThreadPool ();
608
670
if (b .maxThreads > 0 ) {
609
671
threadPool .setMaxThreads (b .maxThreads );
610
672
}
@@ -615,59 +677,29 @@ private void createWebServer(final Builder b) throws IOException {
615
677
this .appDir = getWebAppsPath (b .name );
616
678
this .webAppContext = createWebAppContext (b );
617
679
618
- if (b .useSPNEGO ) {
619
- // Secure the web server with kerberos
620
- setupSpnegoFilter (b , webAppContext );
621
- }
622
-
623
- if (b .enableCORS ) {
624
- setupCORSFilter (b );
625
- }
626
-
627
- Map <String , String > xFrameParams = setHeaders ();
628
- if (b .xFrameEnabled ) {
629
- setupXframeFilter (b ,xFrameParams );
630
- }
631
-
632
- if (b .disableDirListing ) {
633
- disableDirectoryListingOnServlet (webAppContext );
634
- }
635
-
636
- initializeWebServer (b , threadPool .getMaxThreads ());
680
+ initializeWebServer (b );
637
681
}
638
682
639
- private void initializeWebServer (final Builder b , int queueSize ) throws IOException {
683
+ private void initializeWebServer (final Builder b ) throws IOException {
640
684
// Set handling for low resource conditions.
641
685
final LowResourceMonitor low = new LowResourceMonitor (webServer );
642
686
low .setLowResourcesIdleTimeout (10000 );
643
687
webServer .addBean (low );
644
688
645
- Connector connector = createChannelConnector (queueSize , b );
646
- webServer .addConnector (connector );
647
-
648
- RewriteHandler rwHandler = new RewriteHandler ();
649
- rwHandler .setRewriteRequestURI (true );
650
- rwHandler .setRewritePathInfo (false );
651
-
652
- RewriteRegexRule rootRule = new RewriteRegexRule ();
653
- rootRule .setRegex ("^/$" );
654
- rootRule .setReplacement (b .contextRootRewriteTarget );
655
- rootRule .setTerminating (true );
656
-
657
- rwHandler .addRule (rootRule );
658
- rwHandler .setHandler (webAppContext );
659
-
660
- // Configure web application contexts for the web server
661
- ContextHandlerCollection contexts = new ContextHandlerCollection ();
662
- contexts .addHandler (rwHandler );
663
- webServer .setHandler (contexts );
664
-
689
+ // Configure the global context handler collection for the web server
690
+ portHandlerWrapper = new PortHandlerWrapper ();
691
+ webServer .setHandler (portHandlerWrapper );
692
+
693
+ ContextHandlerCollection portHandler = new ContextHandlerCollection ();
694
+ portHandler .addHandler (webAppContext );
695
+ ServerConnector connector = addWebApp (b , webAppContext , portHandler );
696
+
697
+ portHandlerWrapper .addHandler (connector , portHandler );
665
698
666
699
if (b .usePAM ) {
667
- setupPam (b , contexts );
700
+ setupPam (b , portHandlerWrapper );
668
701
}
669
702
670
-
671
703
addServlet ("jmx" , "/jmx" , JMXJsonServlet .class );
672
704
addServlet ("conf" , "/conf" , ConfServlet .class );
673
705
addServlet ("stacks" , "/stacks" , StackServlet .class );
@@ -679,8 +711,7 @@ private void initializeWebServer(final Builder b, int queueSize) throws IOExcept
679
711
if (Files .notExists (tmpDir )) {
680
712
Files .createDirectories (tmpDir );
681
713
}
682
- ServletContextHandler genCtx =
683
- new ServletContextHandler (contexts , "/prof-output" );
714
+ ServletContextHandler genCtx = new ServletContextHandler (portHandler , "/prof-output" );
684
715
setContextAttributes (genCtx .getServletContext (), b .contextAttrs );
685
716
genCtx .addServlet (ProfileOutputServlet .class , "/*" );
686
717
genCtx .setResourceBase (tmpDir .toAbsolutePath ().toString ());
@@ -689,23 +720,17 @@ private void initializeWebServer(final Builder b, int queueSize) throws IOExcept
689
720
LOG .info ("ASYNC_PROFILER_HOME env or -Dasync.profiler.home not specified. Disabling /prof endpoint.." );
690
721
}
691
722
692
- for (Pair <String , Class <? extends HttpServlet >> p : b .servlets ) {
693
- addServlet (p .getFirst (), "/" + p .getFirst (), p .getSecond ());
694
- }
695
-
696
723
b .globalFilters .forEach ((k , v ) -> addFilter (k , v .getFirst (), v .getSecond (), webAppContext .getServletHandler ()));
697
724
698
- ServletContextHandler staticCtx =
699
- new ServletContextHandler (contexts , "/static" );
725
+ ServletContextHandler staticCtx = new ServletContextHandler (portHandler , "/static" );
700
726
staticCtx .setResourceBase (appDir + "/static" );
701
727
staticCtx .addServlet (DefaultServlet .class , "/*" );
702
728
staticCtx .setDisplayName ("static" );
703
729
disableDirectoryListingOnServlet (staticCtx );
704
730
705
731
String logDir = getLogDir (b .conf );
706
732
if (logDir != null ) {
707
- ServletContextHandler logCtx =
708
- new ServletContextHandler (contexts , "/logs" );
733
+ ServletContextHandler logCtx = new ServletContextHandler (portHandler , "/logs" );
709
734
setContextAttributes (logCtx .getServletContext (), b .contextAttrs );
710
735
if (b .useSPNEGO ) {
711
736
setupSpnegoFilter (b ,logCtx );
@@ -716,7 +741,7 @@ private void initializeWebServer(final Builder b, int queueSize) throws IOExcept
716
741
}
717
742
718
743
// Define the global filers for each servlet context except the staticCtx(css style).
719
- Optional <Handler []> handlers = Optional .ofNullable (contexts .getHandlers ());
744
+ Optional <Handler []> handlers = Optional .ofNullable (portHandler .getHandlers ());
720
745
handlers .ifPresent (hs -> Arrays .stream (hs )
721
746
.filter (h -> h instanceof ServletContextHandler && !"static" .equals (((ServletContextHandler ) h ).getDisplayName ()))
722
747
.forEach (h -> b .globalFilters .forEach ((k , v ) ->
@@ -748,7 +773,7 @@ private Map<String, String> getDefaultHeaders() {
748
773
return headers ;
749
774
}
750
775
751
- private void setupXframeFilter (Builder b , Map <String , String > params ) {
776
+ private void setupXframeFilter (Builder b , Map <String , String > params , WebAppContext webAppContext ) {
752
777
FilterHolder holder = new FilterHolder ();
753
778
holder .setClassName (QuotingInputFilter .class .getName ());
754
779
holder .setInitParameters (params );
@@ -811,6 +836,15 @@ public void addServlet(String name, String pathSpec,
811
836
webAppContext .addServlet (holder , pathSpec );
812
837
}
813
838
839
+ private void addServlet (String name , String pathSpec , Class <? extends HttpServlet > clazz ,
840
+ WebAppContext webAppContext ) {
841
+ ServletHolder holder = new ServletHolder (clazz );
842
+ if (name != null ) {
843
+ holder .setName (name );
844
+ }
845
+ webAppContext .addServlet (holder , pathSpec );
846
+ }
847
+
814
848
public void addServlet (String name , String pathSpec , ServletHolder holder ) {
815
849
if (name != null ) {
816
850
holder .setName (name );
@@ -1026,4 +1060,32 @@ private void initHttpHeaderMap() {
1026
1060
}
1027
1061
}
1028
1062
1063
+ class PortHandlerWrapper extends ContextHandlerCollection {
1064
+
1065
+ private final Map <ServerConnector , HandlerCollection > connectorToHandlerMap = new HashMap <>();
1066
+
1067
+ public PortHandlerWrapper () {
1068
+ }
1069
+
1070
+ public void addHandler (ServerConnector connector , HandlerCollection handler ) {
1071
+ connectorToHandlerMap .put (connector , handler );
1072
+ addHandler (handler );
1073
+ }
1074
+
1075
+ @ Override
1076
+ public void handle (String target , Request baseRequest , HttpServletRequest request , HttpServletResponse response ) throws IOException , ServletException {
1077
+ // Determine the connector (port) the request came through
1078
+ int port = request .getServerPort ();
1079
+
1080
+ // Find the handler for the corresponding port
1081
+ Handler handler = connectorToHandlerMap .entrySet ().stream ()
1082
+ .filter (entry -> entry .getKey ().getPort () == port )
1083
+ .map (Map .Entry ::getValue )
1084
+ .findFirst ()
1085
+ .orElseThrow (() -> new IllegalStateException ("No handler found for port " + port ));
1086
+
1087
+ // Delegate the request to the handler
1088
+ handler .handle (target , baseRequest , request , response );
1089
+ }
1090
+ }
1029
1091
}
0 commit comments