Skip to content

Commit 74aad42

Browse files
committed
Update airlift to 258
Airlift disabled RESPONSE_SET_STATUS_OVER_SEND_ERROR in release 257. sendError is problematic in HTTP/2 because it doesn't allow sending status text along with the status code (there isn't such thing as status line in HTTP/2). Other than that, the error mapping happened in two places: explicitly in the ThrowableMapper and implictly in Jetty where status code and lines were used to generate an error page. After this change, the mapping happens in a single place which makes it explicit. All internal errors are rendered in the body of the response.
1 parent e700260 commit 74aad42

File tree

19 files changed

+173
-143
lines changed

19 files changed

+173
-143
lines changed

core/trino-main/src/main/java/io/trino/dispatcher/QueuedStatementResource.java

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import io.trino.execution.QueryState;
3434
import io.trino.server.DisconnectionAwareAsyncResponse;
3535
import io.trino.server.ExternalUriInfo;
36+
import io.trino.server.GoneException;
3637
import io.trino.server.HttpRequestSessionContextFactory;
3738
import io.trino.server.ServerConfig;
3839
import io.trino.server.SessionContext;
@@ -48,21 +49,22 @@
4849
import jakarta.annotation.PostConstruct;
4950
import jakarta.annotation.PreDestroy;
5051
import jakarta.servlet.http.HttpServletRequest;
52+
import jakarta.ws.rs.BadRequestException;
5153
import jakarta.ws.rs.BeanParam;
5254
import jakarta.ws.rs.DELETE;
55+
import jakarta.ws.rs.ForbiddenException;
5356
import jakarta.ws.rs.GET;
57+
import jakarta.ws.rs.NotFoundException;
5458
import jakarta.ws.rs.POST;
5559
import jakarta.ws.rs.Path;
5660
import jakarta.ws.rs.PathParam;
5761
import jakarta.ws.rs.Produces;
5862
import jakarta.ws.rs.QueryParam;
59-
import jakarta.ws.rs.WebApplicationException;
6063
import jakarta.ws.rs.container.Suspended;
6164
import jakarta.ws.rs.core.Context;
6265
import jakarta.ws.rs.core.HttpHeaders;
6366
import jakarta.ws.rs.core.MultivaluedMap;
6467
import jakarta.ws.rs.core.Response;
65-
import jakarta.ws.rs.core.Response.Status;
6668

6769
import java.net.URI;
6870
import java.util.Optional;
@@ -93,10 +95,6 @@
9395
import static io.trino.server.security.ResourceSecurity.AccessType.PUBLIC;
9496
import static io.trino.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR;
9597
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
96-
import static jakarta.ws.rs.core.MediaType.TEXT_PLAIN_TYPE;
97-
import static jakarta.ws.rs.core.Response.Status.BAD_REQUEST;
98-
import static jakarta.ws.rs.core.Response.Status.FORBIDDEN;
99-
import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
10098
import static java.util.Objects.requireNonNull;
10199
import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
102100
import static java.util.concurrent.TimeUnit.MILLISECONDS;
@@ -164,7 +162,7 @@ public Response postStatement(
164162
@BeanParam ExternalUriInfo externalUriInfo)
165163
{
166164
if (isNullOrEmpty(statement)) {
167-
throw badRequest(BAD_REQUEST, "SQL statement is empty");
165+
throw new BadRequestException("SQL statement is empty");
168166
}
169167

170168
Query query = registerQuery(statement, servletRequest, httpHeaders);
@@ -177,7 +175,7 @@ private Query registerQuery(String statement, HttpServletRequest servletRequest,
177175
Optional<String> remoteAddress = Optional.ofNullable(servletRequest.getRemoteAddr());
178176
Optional<Identity> identity = authenticatedIdentity(servletRequest);
179177
if (identity.flatMap(Identity::getPrincipal).map(InternalPrincipal.class::isInstance).orElse(false)) {
180-
throw badRequest(FORBIDDEN, "Internal communication can not be used to start a query");
178+
throw new ForbiddenException("Internal communication can not be used to start a query");
181179
}
182180

183181
MultivaluedMap<String, String> headers = httpHeaders.getRequestHeaders();
@@ -241,7 +239,7 @@ private Query getQuery(QueryId queryId, String slug, long token)
241239
{
242240
Query query = queryManager.getQuery(queryId);
243241
if (query == null || !query.getSlug().isValid(QUEUED_QUERY, slug, token)) {
244-
throw badRequest(NOT_FOUND, "Query not found");
242+
throw new NotFoundException("Query not found");
245243
}
246244
return query;
247245
}
@@ -296,15 +294,6 @@ private static QueryResults createQueryResults(
296294
null);
297295
}
298296

299-
private static WebApplicationException badRequest(Status status, String message)
300-
{
301-
throw new WebApplicationException(
302-
Response.status(status)
303-
.type(TEXT_PLAIN_TYPE)
304-
.entity(message)
305-
.build());
306-
}
307-
308297
private static final class Query
309298
{
310299
private final String query;
@@ -387,7 +376,7 @@ public QueryResults getQueryResults(long token, ExternalUriInfo externalUriInfo)
387376
long lastToken = this.lastToken.get();
388377
// token should be the last token or the next token
389378
if (token != lastToken && token != lastToken + 1) {
390-
throw new WebApplicationException(Response.Status.GONE);
379+
throw new GoneException("Invalid token");
391380
}
392381
// advance (or stay at) the token
393382
this.lastToken.compareAndSet(lastToken, token);
@@ -402,9 +391,7 @@ public QueryResults getQueryResults(long token, ExternalUriInfo externalUriInfo)
402391

403392
DispatchInfo dispatchInfo = dispatchManager.getDispatchInfo(queryId)
404393
// query should always be found, but it may have just been determined to be abandoned
405-
.orElseThrow(() -> new WebApplicationException(Response
406-
.status(NOT_FOUND)
407-
.build()));
394+
.orElseThrow(NotFoundException::new);
408395

409396
return createQueryResults(token + 1, externalUriInfo, dispatchInfo);
410397
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Licensed under the Apache License, Version 2.0 (the "License");
3+
* you may not use this file except in compliance with the License.
4+
* You may obtain a copy of the License at
5+
*
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
*
8+
* Unless required by applicable law or agreed to in writing, software
9+
* distributed under the License is distributed on an "AS IS" BASIS,
10+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the License for the specific language governing permissions and
12+
* limitations under the License.
13+
*/
14+
package io.trino.server;
15+
16+
import jakarta.ws.rs.WebApplicationException;
17+
import jakarta.ws.rs.core.Response;
18+
19+
public class GoneException
20+
extends WebApplicationException
21+
{
22+
public GoneException(String message)
23+
{
24+
super(message, Response.Status.GONE);
25+
}
26+
27+
public GoneException()
28+
{
29+
super(Response.Status.GONE);
30+
}
31+
}

core/trino-main/src/main/java/io/trino/server/HttpRequestSessionContextFactory.java

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,9 @@
3737
import io.trino.sql.parser.SqlParser;
3838
import io.trino.transaction.TransactionId;
3939
import jakarta.servlet.http.HttpServletRequest;
40-
import jakarta.ws.rs.WebApplicationException;
40+
import jakarta.ws.rs.BadRequestException;
4141
import jakarta.ws.rs.core.HttpHeaders;
42-
import jakarta.ws.rs.core.MediaType;
4342
import jakarta.ws.rs.core.MultivaluedMap;
44-
import jakarta.ws.rs.core.Response;
45-
import jakarta.ws.rs.core.Response.Status;
4643

4744
import java.net.URLDecoder;
4845
import java.util.Collection;
@@ -94,14 +91,13 @@ public SessionContext createSessionContext(
9491
MultivaluedMap<String, String> headers,
9592
Optional<String> remoteAddress,
9693
Optional<Identity> authenticatedIdentity)
97-
throws WebApplicationException
9894
{
9995
ProtocolHeaders protocolHeaders;
10096
try {
10197
protocolHeaders = detectProtocol(alternateHeaderName, headers.keySet());
10298
}
10399
catch (ProtocolDetectionException e) {
104-
throw badRequest(e.getMessage());
100+
throw new BadRequestException(e.getMessage());
105101
}
106102
Optional<String> catalog = Optional.ofNullable(trimEmptyToNull(headers.getFirst(protocolHeaders.requestCatalog())));
107103
Optional<String> schema = Optional.ofNullable(trimEmptyToNull(headers.getFirst(protocolHeaders.requestSchema())));
@@ -145,7 +141,7 @@ case ParsedSessionPropertyName(Optional<String> catalogName, String propertyName
145141
// catalog session properties cannot be validated until the transaction has started
146142
catalogSessionProperties.computeIfAbsent(catalogName.orElseThrow(), id -> new HashMap<>()).put(propertyName, propertyValue);
147143
}
148-
default -> throw badRequest(format("Invalid %s header", protocolHeaders.requestSession()));
144+
default -> throw new BadRequestException(format("Invalid %s header", protocolHeaders.requestSession()));
149145
}
150146
}
151147
requireNonNull(catalogSessionProperties, "catalogSessionProperties is null");
@@ -196,7 +192,7 @@ public Identity extractAuthorizedIdentity(Optional<Identity> optionalAuthenticat
196192
protocolHeaders = detectProtocol(alternateHeaderName, headers.keySet());
197193
}
198194
catch (ProtocolDetectionException e) {
199-
throw badRequest(e.getMessage());
195+
throw new BadRequestException(e.getMessage());
200196
}
201197

202198
Identity identity = buildSessionIdentity(optionalAuthenticatedIdentity, protocolHeaders, headers);
@@ -320,7 +316,7 @@ private static SelectedRole toSelectedRole(ProtocolHeaders protocolHeaders, Stri
320316
role = SelectedRole.valueOf(value);
321317
}
322318
catch (IllegalArgumentException e) {
323-
throw badRequest(format("Invalid %s header", protocolHeaders.requestRole()));
319+
throw new BadRequestException(format("Invalid %s header", protocolHeaders.requestRole()));
324320
}
325321
return role;
326322
}
@@ -340,7 +336,7 @@ private static Map<String, String> parseProperty(MultivaluedMap<String, String>
340336
properties.put(nameValue.get(0), urlDecode(nameValue.get(1)));
341337
}
342338
catch (IllegalArgumentException e) {
343-
throw badRequest(format("Invalid %s header: %s", headerName, e));
339+
throw new BadRequestException(format("Invalid %s header: %s", headerName, e));
344340
}
345341
}
346342
return properties;
@@ -374,10 +370,10 @@ private static ResourceEstimates parseResourceEstimate(ProtocolHeaders protocolH
374370
builder.setPeakMemory(DataSize.valueOf(value));
375371
return;
376372
}
377-
throw badRequest(format("Unsupported resource name %s", name));
373+
throw new BadRequestException(format("Unsupported resource name %s", name));
378374
}
379375
catch (IllegalArgumentException e) {
380-
throw badRequest(format("Unsupported format for resource estimate '%s': %s", value, e));
376+
throw new BadRequestException(format("Unsupported format for resource estimate '%s': %s", value, e));
381377
}
382378
});
383379

@@ -397,7 +393,7 @@ private static ParsedSessionPropertyName parseSessionPropertyName(String value)
397393
private static void assertRequest(boolean expression, String format, Object... args)
398394
{
399395
if (!expression) {
400-
throw badRequest(format(format, args));
396+
throw new BadRequestException(format(format, args));
401397
}
402398
}
403399

@@ -410,7 +406,7 @@ private Map<String, String> parsePreparedStatementsHeaders(ProtocolHeaders proto
410406
statementName = urlDecode(key);
411407
}
412408
catch (IllegalArgumentException e) {
413-
throw badRequest(format("Invalid %s header: %s", protocolHeaders.requestPreparedStatement(), e.getMessage()));
409+
throw new BadRequestException(format("Invalid %s header: %s", protocolHeaders.requestPreparedStatement(), e.getMessage()));
414410
}
415411
String sqlString = preparedStatementEncoder.decodePreparedStatementFromHeader(value);
416412

@@ -420,7 +416,7 @@ private Map<String, String> parsePreparedStatementsHeaders(ProtocolHeaders proto
420416
sqlParser.createStatement(sqlString);
421417
}
422418
catch (ParsingException e) {
423-
throw badRequest(format("Invalid %s header: %s", protocolHeaders.requestPreparedStatement(), e.getMessage()));
419+
throw new BadRequestException(format("Invalid %s header: %s", protocolHeaders.requestPreparedStatement(), e.getMessage()));
424420
}
425421

426422
preparedStatements.put(statementName, sqlString);
@@ -439,19 +435,10 @@ private static Optional<TransactionId> parseTransactionId(String transactionId)
439435
return Optional.of(TransactionId.valueOf(transactionId));
440436
}
441437
catch (Exception e) {
442-
throw badRequest(e.getMessage());
438+
throw new BadRequestException(e.getMessage());
443439
}
444440
}
445441

446-
private static WebApplicationException badRequest(String message)
447-
{
448-
throw new WebApplicationException(message, Response
449-
.status(Status.BAD_REQUEST)
450-
.type(MediaType.TEXT_PLAIN)
451-
.entity(message)
452-
.build());
453-
}
454-
455442
private static String trimEmptyToNull(String value)
456443
{
457444
return emptyToNull(nullToEmpty(value).trim());

core/trino-main/src/main/java/io/trino/server/QueryResource.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public Response getQueryInfo(@PathParam("queryId") QueryId queryId, @QueryParam(
9797
Optional<QueryInfo> queryInfo = dispatchManager.getFullQueryInfo(queryId)
9898
.map(info -> pruned ? pruneQueryInfo(info, info.getVersion()) : info);
9999
if (queryInfo.isEmpty()) {
100-
return Response.status(Status.GONE).build();
100+
throw new GoneException();
101101
}
102102
try {
103103
checkCanViewQueryOwnedBy(sessionContextFactory.extractAuthorizedIdentity(servletRequest, httpHeaders), queryInfo.get().getSession().toIdentity(), accessControl);
@@ -165,7 +165,7 @@ private Response failQuery(QueryId queryId, TrinoException queryException, HttpS
165165
throw new ForbiddenException();
166166
}
167167
catch (NoSuchElementException e) {
168-
return Response.status(Status.GONE).build();
168+
throw new GoneException();
169169
}
170170
}
171171
}

core/trino-main/src/main/java/io/trino/server/QueryStateInfoResource.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
import jakarta.servlet.http.HttpServletRequest;
2525
import jakarta.ws.rs.ForbiddenException;
2626
import jakarta.ws.rs.GET;
27+
import jakarta.ws.rs.NotFoundException;
2728
import jakarta.ws.rs.Path;
2829
import jakarta.ws.rs.PathParam;
2930
import jakarta.ws.rs.Produces;
3031
import jakarta.ws.rs.QueryParam;
31-
import jakarta.ws.rs.WebApplicationException;
3232
import jakarta.ws.rs.core.Context;
3333
import jakarta.ws.rs.core.HttpHeaders;
3434
import jakarta.ws.rs.core.MediaType;
@@ -46,7 +46,6 @@
4646
import static io.trino.server.QueryStateInfo.createQueryStateInfo;
4747
import static io.trino.server.QueryStateInfo.createQueuedQueryStateInfo;
4848
import static io.trino.server.security.ResourceSecurity.AccessType.AUTHENTICATED_USER;
49-
import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
5049
import static java.util.Objects.requireNonNull;
5150

5251
@Path("/v1/queryState")
@@ -108,7 +107,6 @@ private QueryStateInfo getQueryStateInfo(BasicQueryInfo queryInfo)
108107
@Path("{queryId}")
109108
@Produces(MediaType.APPLICATION_JSON)
110109
public QueryStateInfo getQueryStateInfo(@PathParam("queryId") String queryId, @Context HttpServletRequest servletRequest, @Context HttpHeaders httpHeaders)
111-
throws WebApplicationException
112110
{
113111
try {
114112
BasicQueryInfo queryInfo = dispatchManager.getQueryInfo(new QueryId(queryId));
@@ -119,7 +117,7 @@ public QueryStateInfo getQueryStateInfo(@PathParam("queryId") String queryId, @C
119117
throw new ForbiddenException();
120118
}
121119
catch (NoSuchElementException e) {
122-
throw new WebApplicationException(NOT_FOUND);
120+
throw new NotFoundException();
123121
}
124122
}
125123
}

core/trino-main/src/main/java/io/trino/server/ResourceGroupStateInfoResource.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
import io.trino.spi.resourcegroups.ResourceGroupId;
2020
import jakarta.ws.rs.Encoded;
2121
import jakarta.ws.rs.GET;
22+
import jakarta.ws.rs.NotFoundException;
2223
import jakarta.ws.rs.Path;
2324
import jakarta.ws.rs.PathParam;
2425
import jakarta.ws.rs.Produces;
25-
import jakarta.ws.rs.WebApplicationException;
2626
import jakarta.ws.rs.core.MediaType;
2727

2828
import java.net.URLDecoder;
@@ -31,7 +31,6 @@
3131
import static com.google.common.base.Strings.isNullOrEmpty;
3232
import static com.google.common.collect.ImmutableList.toImmutableList;
3333
import static io.trino.server.security.ResourceSecurity.AccessType.MANAGEMENT_READ;
34-
import static jakarta.ws.rs.core.Response.Status.NOT_FOUND;
3534
import static java.nio.charset.StandardCharsets.UTF_8;
3635
import static java.util.Objects.requireNonNull;
3736

@@ -59,9 +58,9 @@ public ResourceGroupInfo getQueryStateInfos(@PathParam("resourceGroupId") String
5958
Arrays.stream(resourceGroupIdString.split("/"))
6059
.map(ResourceGroupStateInfoResource::urlDecode)
6160
.collect(toImmutableList())))
62-
.orElseThrow(() -> new WebApplicationException(NOT_FOUND));
61+
.orElseThrow(NotFoundException::new);
6362
}
64-
throw new WebApplicationException(NOT_FOUND);
63+
throw new NotFoundException();
6564
}
6665

6766
private static String urlDecode(String value)

0 commit comments

Comments
 (0)