22
33import com .fasterxml .jackson .core .JsonProcessingException ;
44import com .fasterxml .jackson .databind .ObjectMapper ;
5+ import lombok .extern .slf4j .Slf4j ;
56import org .apache .commons .lang3 .StringUtils ;
67import org .apache .commons .lang3 .text .StrSubstitutor ;
78import org .springframework .beans .factory .annotation .Autowired ;
8- import org .springframework .beans .factory .annotation .Value ;
99import org .springframework .core .env .Environment ;
1010import org .springframework .core .io .ClassPathResource ;
1111import org .springframework .http .MediaType ;
12+ import org .springframework .security .web .csrf .CsrfToken ;
1213import org .springframework .stereotype .Controller ;
1314import org .springframework .util .StreamUtils ;
15+ import org .springframework .web .bind .annotation .GetMapping ;
1416import org .springframework .web .bind .annotation .PathVariable ;
15- import org .springframework .web .bind .annotation .RequestMapping ;
1617import org .springframework .web .bind .annotation .RequestParam ;
1718
1819import javax .annotation .PostConstruct ;
2829/**
2930 * @author Andrew Potter
3031 */
32+ @ Slf4j
3133@ Controller
3234public class GraphiQLController {
3335
@@ -36,30 +38,6 @@ public class GraphiQLController {
3638 private static final String GRAPHIQL = "graphiql" ;
3739 private static final String FAVICON_GRAPHQL_ORG = "//graphql.org/img/favicon.png" ;
3840
39- @ Value ("${graphiql.endpoint.graphql:/graphql}" )
40- private String graphqlEndpoint ;
41-
42- @ Value ("${graphiql.endpoint.subscriptions:/subscriptions}" )
43- private String subscriptionsEndpoint ;
44-
45- @ Value ("${graphiql.static.basePath:/}" )
46- private String staticBasePath ;
47-
48- @ Value ("${graphiql.pageTitle:GraphiQL}" )
49- private String pageTitle ;
50-
51- @ Value ("${graphiql.cdn.enabled:false}" )
52- private Boolean graphiqlCdnEnabled ;
53-
54- @ Value ("${graphiql.cdn.version:0.13.0}" )
55- private String graphiqlCdnVersion ;
56-
57- @ Value ("${graphiql.subscriptions.timeout:30}" )
58- private Integer subscriptionsTimeout ;
59-
60- @ Value ("${graphiql.subscriptions.reconnect:false}" )
61- private Boolean subscriptionsReconnect ;
62-
6341 @ Autowired
6442 private Environment environment ;
6543
@@ -68,7 +46,7 @@ public class GraphiQLController {
6846
6947 private String template ;
7048 private String props ;
71- private String headers ;
49+ private Properties headerProperties ;
7250
7351 @ PostConstruct
7452 public void onceConstructed () throws IOException {
@@ -87,12 +65,11 @@ private void loadProps() throws IOException {
8765 props = new PropsLoader (environment ).load ();
8866 }
8967
90- private void loadHeaders () throws JsonProcessingException {
68+ private void loadHeaders () {
9169 PropertyGroupReader propertyReader = new PropertyGroupReader (environment , "graphiql.headers." );
92- Properties headerProperties = propertyReader .load ();
70+ headerProperties = propertyReader .load ();
9371 addIfAbsent (headerProperties , "Accept" );
9472 addIfAbsent (headerProperties , "Content-Type" );
95- this .headers = new ObjectMapper ().writeValueAsString (headerProperties );
9673 }
9774
9875 private void addIfAbsent (Properties headerProperties , String header ) {
@@ -101,26 +78,35 @@ private void addIfAbsent(Properties headerProperties, String header) {
10178 }
10279 }
10380
104- @ RequestMapping (value = "${graphiql.mapping:/graphiql}" )
81+ @ GetMapping (value = "${graphiql.mapping:/graphiql}" )
10582 public void graphiql (HttpServletRequest request , HttpServletResponse response , @ PathVariable Map <String , String > params ) throws IOException {
10683 response .setContentType ("text/html; charset=UTF-8" );
84+ Object csrf = request .getAttribute ("_csrf" );
85+ if (csrf != null ) {
86+ CsrfToken csrfToken = (CsrfToken ) csrf ;
87+ headerProperties .setProperty (csrfToken .getHeaderName (), csrfToken .getToken ());
88+ }
10789
10890 Map <String , String > replacements = getReplacements (
10991 constructGraphQlEndpoint (request , params ),
110- request .getContextPath () + subscriptionsEndpoint ,
111- request .getContextPath () + staticBasePath
92+ request .getContextPath () + graphiQLProperties . getEndpoint (). getSubscriptions () ,
93+ request .getContextPath () + graphiQLProperties . getSTATIC (). getBasePath ()
11294 );
11395
11496 String populatedTemplate = StrSubstitutor .replace (template , replacements );
11597 response .getOutputStream ().write (populatedTemplate .getBytes (Charset .defaultCharset ()));
11698 }
11799
118- private Map <String , String > getReplacements (String graphqlEndpoint , String subscriptionsEndpoint , String staticBasePath ) {
100+ private Map <String , String > getReplacements (
101+ String graphqlEndpoint ,
102+ String subscriptionsEndpoint ,
103+ String staticBasePath
104+ ) {
119105 Map <String , String > replacements = new HashMap <>();
120106 replacements .put ("graphqlEndpoint" , graphqlEndpoint );
121107 replacements .put ("subscriptionsEndpoint" , subscriptionsEndpoint );
122108 replacements .put ("staticBasePath" , staticBasePath );
123- replacements .put ("pageTitle" , pageTitle );
109+ replacements .put ("pageTitle" , graphiQLProperties . getPageTitle () );
124110 replacements .put ("pageFavicon" , getResourceUrl (staticBasePath , "favicon.ico" , FAVICON_GRAPHQL_ORG ));
125111 replacements .put ("es6PromiseJsUrl" , getResourceUrl (staticBasePath , "es6-promise.auto.min.js" ,
126112 joinCdnjsPath ("es6-promise" , "4.1.1" , "es6-promise.auto.min.js" )));
@@ -131,19 +117,23 @@ private Map<String, String> getReplacements(String graphqlEndpoint, String subsc
131117 replacements .put ("reactDomJsUrl" , getResourceUrl (staticBasePath , "react-dom.min.js" ,
132118 joinCdnjsPath ("react-dom" , "16.8.3" , "umd/react-dom.production.min.js" )));
133119 replacements .put ("graphiqlCssUrl" , getResourceUrl (staticBasePath , "graphiql.min.css" ,
134- joinJsDelivrPath (GRAPHIQL , graphiqlCdnVersion , "graphiql.css" )));
120+ joinJsDelivrPath (GRAPHIQL , graphiQLProperties . getCdn (). getVersion () , "graphiql.css" )));
135121 replacements .put ("graphiqlJsUrl" , getResourceUrl (staticBasePath , "graphiql.min.js" ,
136- joinJsDelivrPath (GRAPHIQL , graphiqlCdnVersion , "graphiql.min.js" )));
122+ joinJsDelivrPath (GRAPHIQL , graphiQLProperties . getCdn (). getVersion () , "graphiql.min.js" )));
137123 replacements .put ("subscriptionsTransportWsBrowserClientUrl" , getResourceUrl (staticBasePath ,
138124 "subscriptions-transport-ws-browser-client.js" ,
139125 joinJsDelivrPath ("subscriptions-transport-ws" , "0.9.15" , "browser/client.js" )));
140126 replacements .put ("graphiqlSubscriptionsFetcherBrowserClientUrl" , getResourceUrl (staticBasePath ,
141127 "graphiql-subscriptions-fetcher-browser-client.js" ,
142128 joinJsDelivrPath ("graphiql-subscriptions-fetcher" , "0.0.2" , "browser/client.js" )));
143129 replacements .put ("props" , props );
144- replacements .put ("headers" , headers );
145- replacements .put ("subscriptionClientTimeout" , String .valueOf (subscriptionsTimeout * 1000 ));
146- replacements .put ("subscriptionClientReconnect" , String .valueOf (subscriptionsReconnect ));
130+ try {
131+ replacements .put ("headers" , new ObjectMapper ().writeValueAsString (headerProperties ));
132+ } catch (JsonProcessingException e ) {
133+ log .error ("Cannot serialize headers" , e );
134+ }
135+ replacements .put ("subscriptionClientTimeout" , String .valueOf (graphiQLProperties .getSubscriptions ().getTimeout () * 1000 ));
136+ replacements .put ("subscriptionClientReconnect" , String .valueOf (graphiQLProperties .getSubscriptions ().isReconnect ()));
147137 replacements .put ("editorThemeCss" , getEditorThemeCssURL ());
148138 return replacements ;
149139 }
@@ -161,7 +151,7 @@ private String getEditorThemeCssURL() {
161151 }
162152
163153 private String getResourceUrl (String staticBasePath , String staticFileName , String cdnUrl ) {
164- if (graphiqlCdnEnabled && StringUtils .isNotBlank (cdnUrl )) {
154+ if (graphiQLProperties . getCdn (). isEnabled () && StringUtils .isNotBlank (cdnUrl )) {
165155 return cdnUrl ;
166156 }
167157 return joinStaticPath (staticBasePath , staticFileName );
@@ -180,7 +170,7 @@ private String joinJsDelivrPath(String library, String cdnVersion, String cdnFil
180170 }
181171
182172 private String constructGraphQlEndpoint (HttpServletRequest request , @ RequestParam Map <String , String > params ) {
183- String endpoint = graphqlEndpoint ;
173+ String endpoint = graphiQLProperties . getEndpoint (). getGraphql () ;
184174 for (Map .Entry <String , String > param : params .entrySet ()) {
185175 endpoint = endpoint .replaceAll ("\\ {" + param .getKey () + "}" , param .getValue ());
186176 }
0 commit comments