-
-
Notifications
You must be signed in to change notification settings - Fork 170
/
ResponseHelper.java
257 lines (233 loc) · 10.5 KB
/
ResponseHelper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
/*-
* ========================LICENSE_START=================================
* restheart-mongodb
* %%
* Copyright (C) 2014 - 2024 SoftInstigate
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* =========================LICENSE_END==================================
*/
package org.restheart.mongodb.utils;
import org.bson.BsonDocument;
import org.bson.BsonValue;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.restheart.utils.HttpStatus;
import com.mongodb.MongoException;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.Headers;
/**
*
* @author Andrea Di Cesare {@literal <andrea@softinstigate.com>}
*/
public class ResponseHelper {
/**
* Set the ETag in the response's header
*
* @param exchange
* @param etag
*/
protected static void setETagHeader(final HttpServerExchange exchange, final String etag) {
exchange.getResponseHeaders().put(Headers.ETAG, etag);
}
/**
*
* @param exchange
* @param properties
*/
public static void injectEtagHeader(HttpServerExchange exchange, BsonDocument properties) {
if (properties == null) {
return;
}
var _etag = properties.get("_etag");
if (_etag == null) {
return;
}
if (_etag.isObjectId()) {
setETagHeader(exchange, _etag.asObjectId().getValue().toString());
} else if (_etag.isString()) {
setETagHeader(exchange, _etag.asString().getValue());
}
}
/**
*
* @param exchange
* @param properties
*/
public static void injectEtagHeader(HttpServerExchange exchange, Document properties) {
if (properties == null) {
return;
}
var _etag = properties.get("_etag");
if (_etag == null) {
return;
}
if (_etag instanceof ObjectId) {
setETagHeader(exchange, _etag.toString());
} else if (_etag instanceof String setag) {
setETagHeader(exchange, setag);
}
}
/**
*
* @param exchange
* @param etag
*/
public static void injectEtagHeader(HttpServerExchange exchange, Object etag) {
if (etag == null) {
return;
}
if (etag instanceof BsonValue _etag) {
if (_etag.isObjectId()) {
setETagHeader(exchange, _etag.asObjectId().getValue().toString());
} else if (_etag.isString()) {
setETagHeader(exchange, _etag.asString().getValue());
}
} else if (etag instanceof ObjectId) {
setETagHeader(exchange, etag.toString());
} else if (etag instanceof String) {
setETagHeader(exchange, (String) etag);
}
}
/**
*
* @param code mongodb error code from MongoException.getCode()
* @return
*/
public static int getHttpStatusFromErrorCode(int code) {
return switch (code) {
// Unknown top level operator
case 2 -> HttpStatus.SC_BAD_REQUEST;
// The MongoDB user does not have enough permissions to execute this operation.
case 13 -> HttpStatus.SC_FORBIDDEN;
// Wrong MongoDB user credentials
case 18 -> HttpStatus.SC_FORBIDDEN;
// Write request for sharded collection must specify the shardkey.
case 61 -> HttpStatus.SC_BAD_REQUEST;
// Update tried to change the immutable shardkey
case 66 -> HttpStatus.SC_FORBIDDEN;
// Invalid database name
case 73 -> HttpStatus.SC_BAD_REQUEST;
// Document failed validation
case 121 -> HttpStatus.SC_BAD_REQUEST;
//WriteConflict
case 112 -> HttpStatus.SC_CONFLICT;
// Cannot start transaction X on session Y because a newer transaction Z has already started
// transaction number X does not match any in-progress transactions
// Transaction X has been committed.
case 225,251,256 -> HttpStatus.SC_NOT_ACCEPTABLE;
// error 11000 is duplicate key error
// happens when the _id and a filter are specified,
// the document exists but does not match the filter
case 11000 ->HttpStatus.SC_CONFLICT;
// db already exists with different case
case 13297 -> HttpStatus.SC_CONFLICT;
// 56, 40353 FieldPath must not end with a '.'
// 40352 FieldPath cannot be constructed with empty string
// 51091 Regular expression is invalid: unmatched parentheses
// 51108 Invalid flag in regex options
// 16410 FieldPath field names may not start with '$'
case 56, 40353, 40352, 51091, 51108, 40323, 16410 -> HttpStatus.SC_BAD_REQUEST;
// 31253 Cannot do inclusion on field xxxx in exclusion projection
case 31253 -> HttpStatus.SC_BAD_REQUEST;
// 15974 Illegal key in $sort specification
// 17312 $meta is the only expression supported by $sort right now
// 31138 Illegal $meta sort
case 15974, 17312, 31138 -> HttpStatus.SC_BAD_REQUEST;
case 15998 -> HttpStatus.SC_BAD_REQUEST;
// 31249 Path collision
case 31249 -> HttpStatus.SC_BAD_REQUEST;
// 168 InvalidPipelineOperator
case 168 -> HttpStatus.SC_BAD_REQUEST;
// 17276 Use of undefined variable
case 17276 -> HttpStatus.SC_BAD_REQUEST;
// 1728, Can't canonicalize query: BadValue Projection cannot have a mix of inclusion and exclusion (old error message)
// 31254 Cannot do exclusion on field x in inclusion projection
case 17287, 31254 -> HttpStatus.SC_BAD_REQUEST;
// 241 ConversionFailure
case 241 -> HttpStatus.SC_BAD_REQUEST;
default -> HttpStatus.SC_INTERNAL_SERVER_ERROR;
};
}
/**
*
* @param me the MongoException
* @return
*/
public static String getMessageFromMongoException(MongoException me) {
var code = me.getCode();
return switch(code) {
// Query failed with error code 51091 and error message 'Regular expression is invalid: unmatched parentheses'
// Query failed with error code 51108 with name 'Location51108' and error message 'invalid flag in regex options: z' on server 127.0.0.1:27017'
// Command failed with error 31249 (Location31249): 'Path collision at page.children.children.displayname remaining portion children.children.displayname' on server...
case 2, 51091, 51108, 31249, 168, 17276, 31254 -> {
var msg = me.getMessage();
var b = msg.indexOf(": '");
var e = msg.indexOf("' on server");
if (b >= 0 && e >= 0) {
yield "Invalid query parameter: " + msg.substring(b+3, e).strip();
} else {
yield msg;
}
}
default -> getMessageFromErrorCode(code);
};
}
/**
*
* @param code mongodb error code from MongoException.getCode()
* @return
*/
public static String getMessageFromErrorCode(int code) {
return switch(code) {
case 13 -> "The MongoDB user does not have enough permissions to execute this operation";
case 18 -> "Wrong MongoDB user credentials (wrong password or need to specify the authentication dababase with 'authSource=<db>' option in mongo-uri)";
case 61 -> "Write request for sharded collection must specify the shardkey. Use the 'shardkey' query parameter";
case 66 -> "Update tried to change the immutable shardkey";
case 73 -> "Invalid database name";
case 121 -> "Document failed validation";
case 112 -> "Write conflict inside transaction";
// Cannot start transaction X on session Y because a newer transaction Z has already started// Cannot start transaction X on session Y because a newer transaction Z has already started
case 225 -> "The given transaction is not in-progress";
// transaction number X does not match any in-progress transactions
case 251 -> "The given transaction is not in-progress";
// Transaction X has been committed.
case 256 -> "The given transaction is not in-progress";
// error 11000 is duplicate key error
// can happens for
// - insert requests but _id already exists
// - for upsert/updates with the _id and a filter, and the update document does not match the filter
// - a unique index exists, and the document duplicates an existing key
case 11000 -> "Duplicate key error (insert with existing _id, update a document not matching specified filter or unique index violation)";
// FieldPath must not end with a '.'
case 56, 40353 -> "FieldPath must not end with a '.'";
case 40352 -> "FieldPath cannot be constructed with empty string";
case 16410 -> "FieldPath field names may not start with '$'";
case 13297 -> "Db already exists with different case";
// 31253 Cannot do inclusion on field xxxx in exclusion projection
case 17287, 31253 -> "Keys projection cannot have a mix of inclusion and exclusion";
// 15974 Illegal key in $sort specification
// 17312 $meta is the only expression supported by $sort right now
case 15974, 17312 -> "Invalid sort parameter";
// 31138 Illegal $meta sort
case 31138 -> "Invalid $meta sort";
case 40323 -> "A pipeline stage specification object must contain exactly one field.";
case 15998 -> "FieldPath field names may not be empty strings";
case 241 -> "Failed to parse number in $convert";
default -> "Error handling the request, see log for more information";
};
}
private ResponseHelper() {
}
}