Skip to content

Commit 04f5f8d

Browse files
committed
[grid] Implementing CORS support managed by --allow-cors option and adding support for OPTIONS requests to GraphqlHandler
1 parent 8ac2beb commit 04f5f8d

File tree

10 files changed

+37
-8
lines changed

10 files changed

+37
-8
lines changed

java/client/src/org/openqa/selenium/remote/http/HttpMethod.java

+1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ public enum HttpMethod {
2121
DELETE,
2222
GET,
2323
POST,
24+
OPTIONS
2425
}

java/client/src/org/openqa/selenium/remote/http/Route.java

+9
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import static org.openqa.selenium.remote.http.Contents.utf8String;
3636
import static org.openqa.selenium.remote.http.HttpMethod.DELETE;
3737
import static org.openqa.selenium.remote.http.HttpMethod.GET;
38+
import static org.openqa.selenium.remote.http.HttpMethod.OPTIONS;
3839
import static org.openqa.selenium.remote.http.HttpMethod.POST;
3940
import static org.openqa.selenium.remote.http.UrlPath.ROUTE_PREFIX_KEY;
4041

@@ -111,6 +112,14 @@ public static TemplatizedRouteConfig post(String template) {
111112
urlTemplate);
112113
}
113114

115+
public static TemplatizedRouteConfig options(String template) {
116+
UrlTemplate urlTemplate = new UrlTemplate(Require.nonNull("URL template", template));
117+
118+
return new TemplatizedRouteConfig(
119+
new MatchesHttpMethod(OPTIONS).and(new MatchesTemplate(urlTemplate)),
120+
urlTemplate);
121+
}
122+
114123
public static NestedRouteConfig prefix(String prefix) {
115124
Require.nonNull("Prefix", prefix);
116125
Require.stateCondition(!prefix.isEmpty(), "Prefix to use must not be of 0 length");

java/server/src/org/openqa/selenium/grid/commands/Hub.java

+1
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ protected Handlers createHandlers(Config config) {
195195
ui,
196196
router.with(networkOptions.getSpecComplianceChecks()),
197197
Route.prefix("/wd/hub").to(combine(router.with(networkOptions.getSpecComplianceChecks()))),
198+
Route.options("/graphql").to(() -> graphqlHandler),
198199
Route.post("/graphql").to(() -> graphqlHandler),
199200
Route.get("/readyz").to(() -> readinessCheck));
200201

java/server/src/org/openqa/selenium/grid/commands/Standalone.java

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ protected Handlers createHandlers(Config config) {
199199
ui,
200200
router,
201201
Route.prefix("/wd/hub").to(combine(router)),
202+
Route.options("/graphql").to(() -> graphqlHandler),
202203
Route.post("/graphql").to(() -> graphqlHandler),
203204
Route.get("/readyz").to(() -> readinessCheck));
204205

java/server/src/org/openqa/selenium/grid/graphql/GraphqlHandler.java

+4
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import static org.openqa.selenium.json.Json.JSON_UTF_8;
5555
import static org.openqa.selenium.json.Json.MAP_TYPE;
5656
import static org.openqa.selenium.remote.http.Contents.utf8String;
57+
import static org.openqa.selenium.remote.http.HttpMethod.OPTIONS;
5758
import static org.openqa.selenium.remote.tracing.HttpTracing.newSpanAsChildOf;
5859
import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE;
5960
import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE_EVENT;
@@ -105,6 +106,9 @@ public GraphqlHandler(Tracer tracer, Distributor distributor, NewSessionQueuer n
105106

106107
@Override
107108
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
109+
if (req.getMethod() == OPTIONS) {
110+
return new HttpResponse();
111+
}
108112
try (Span span = newSpanAsChildOf(tracer, req, "grid.status")) {
109113
HttpResponse response;
110114
Map<String, Object> inputs = JSON.toType(Contents.string(req), MAP_TYPE);

java/server/src/org/openqa/selenium/grid/router/httpd/RouterServer.java

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ protected Handlers createHandlers(Config config) {
142142

143143
Route handler = Route.combine(
144144
new Router(tracer, clientFactory, sessions, queuer, distributor).with(networkOptions.getSpecComplianceChecks()),
145+
Route.options("/graphql").to(() -> graphqlHandler),
145146
Route.post("/graphql").to(() -> graphqlHandler),
146147
get("/readyz").to(() -> req -> new HttpResponse().setStatus(HTTP_NO_CONTENT)));
147148

java/server/src/org/openqa/selenium/netty/server/NettyServer.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public class NettyServer implements Server<NettyServer> {
5757
private final HttpHandler handler;
5858
private final BiFunction<String, Consumer<Message>, Optional<Consumer<Message>>> websocketHandler;
5959
private final SslContext sslCtx;
60+
private final boolean allowCors;
6061

6162
private Channel channel;
6263

@@ -102,6 +103,7 @@ public NettyServer(
102103
workerGroup = new NioEventLoopGroup();
103104

104105
port = options.getPort();
106+
allowCors = options.getAllowCORS();
105107

106108
try {
107109
externalUrl = options.getExternalUri().toURL();
@@ -142,7 +144,7 @@ public NettyServer start() {
142144
b.group(bossGroup, workerGroup)
143145
.channel(NioServerSocketChannel.class)
144146
.handler(new LoggingHandler(LogLevel.DEBUG))
145-
.childHandler(new SeleniumHttpInitializer(sslCtx, handler, websocketHandler));
147+
.childHandler(new SeleniumHttpInitializer(sslCtx, handler, websocketHandler, allowCors));
146148

147149
try {
148150
channel = b.bind(port).sync().channel();

java/server/src/org/openqa/selenium/netty/server/ResponseConverter.java

+11
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@
4040
public class ResponseConverter extends ChannelOutboundHandlerAdapter {
4141

4242
private static final int CHUNK_SIZE = 1024 * 1024;
43+
private final boolean allowCors;
44+
45+
public ResponseConverter(boolean allowCors) {
46+
this.allowCors = allowCors;
47+
}
4348

4449
@Override
4550
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise)
@@ -100,5 +105,11 @@ private void copyHeaders(HttpResponse seResponse, DefaultHttpResponse first) {
100105
first.headers().add(name, value);
101106
}
102107
}
108+
109+
if (allowCors) {
110+
first.headers().add("Access-Control-Allow-Origin", "*");
111+
first.headers().add("Access-Control-Allow-Methods", "GET,POST,DELETE");
112+
first.headers().add("Access-Control-Allow-Headers", "Accept,Content-Type");
113+
}
103114
}
104115
}

java/server/src/org/openqa/selenium/netty/server/SeleniumHttpInitializer.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,17 @@ class SeleniumHttpInitializer extends ChannelInitializer<SocketChannel> {
4040
private HttpHandler seleniumHandler;
4141
private final BiFunction<String, Consumer<Message>, Optional<Consumer<Message>>> webSocketHandler;
4242
private SslContext sslCtx;
43+
private final boolean allowCors;
4344

4445
SeleniumHttpInitializer(
4546
SslContext sslCtx,
4647
HttpHandler seleniumHandler,
47-
BiFunction<String, Consumer<Message>, Optional<Consumer<Message>>> webSocketHandler) {
48+
BiFunction<String, Consumer<Message>, Optional<Consumer<Message>>> webSocketHandler,
49+
boolean allowCors) {
4850
this.sslCtx = sslCtx;
4951
this.seleniumHandler = Require.nonNull("HTTP handler", seleniumHandler);
5052
this.webSocketHandler = Require.nonNull("WebSocket handler", webSocketHandler);
53+
this.allowCors = allowCors;
5154
}
5255

5356
@Override
@@ -68,7 +71,7 @@ protected void initChannel(SocketChannel ch) {
6871

6972
// Regular HTTP magic
7073
ch.pipeline().addLast("se-request", new RequestConverter());
71-
ch.pipeline().addLast("se-response", new ResponseConverter());
74+
ch.pipeline().addLast("se-response", new ResponseConverter(allowCors));
7275
ch.pipeline().addLast("se-handler", new SeleniumHandler(seleniumHandler));
7376
}
7477
}

javascript/grid-ui/src/config.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,9 @@ export const GridConfig = {
1818
},
1919

2020
/** Server config */
21-
// For development
22-
// Install https://www.npmjs.com/package/cors-anywhere on an empty directory
23-
// Run: node node_modules/cors-anywhere/server.js
24-
// Then start the Selenium Server on port 4444 (which is the default).
2521
serverUri:
2622
process.env.NODE_ENV === "development"
27-
? "http://localhost:8080/http://localhost:4444/graphql"
23+
? "http://localhost:4444/graphql"
2824
: document.location.protocol + "//" + document.location.host + "/graphql",
2925

3026
/** Keybinds config */

0 commit comments

Comments
 (0)