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