private RouteMeta getByFullClassAndName(String name) { RouteMeta meta = fullClassAndNameToRoute.get(name); if(meta == null) throw new RouteNotFoundException("route="+name+" not found."); return meta; }
@Override public void validateNullValue() { //by default, params are required unless some sort of @Nullable annotation //is used. for(Annotation annotation : annotations) { Class<? extends Annotation> annotationType = annotation.annotationType(); if(annotationType.equals(Nullable.class)) return; //null is allowed so just return } throw new DataMismatchException("On method="+method+" the parameter="+this+" did not have any @Nullable annotation so data is required but none came in"); }
public List<Object> createArgs(Method m, RequestContext ctx, BodyContentBinder binder) { RouterRequest req = ctx.getRequest(); try { return createArgsImpl(m, ctx, binder); } catch(DataMismatchException e) { if(req.method == HttpMethod.GET) { //For GET with query params or path urls, if we can't convert, it should be a 404... //This is because a human user typed in the wrong url so they should get back not found throw new NotFoundException(e); } else { //For POST with multipart, this should be a 500 because a human user does NOT type in post //urls and instead the developer typed in the wrong url and an issue needs to be fixed(or //some hacker is doing something so internal error there is fine as well) if(req.multiPartFields.size() > 0) throw new IllegalArgumentException(e); else //for apis that POST, this is a client error(or developer error when testing) throw new ClientDataError(e); } } }
public CompletableFuture<Void> invoke2(MatchResult result, RequestContext requestCtx, ResponseStreamer responseCb, ErrorRoutes errorRoutes) { //This makes us consistent with other NotFoundExceptions and without the cost of //throwing an exception and filling in stack trace... //We could convert the exc. to FastException and override method so stack is not filled in but that //can get very annoying RouteMeta meta = result.getMeta(); Route route = meta.getRoute(); RouteType routeType = route.getRouteType(); if(routeType == RouteType.NOT_FOUND) { CompletableFuture<Void> future = new CompletableFuture<Void>(); future.completeExceptionally(new NotFoundException("route not found")); return future; } return invokeImpl(result, meta.getService222(), requestCtx, responseCb); }
@SuppressWarnings("unchecked") @Override public <T> T unmarshal(Class<T> entityClass, byte[] data) { try { if(data.length == 0) throw new ClientDataError("Client did not provide a json request in the body of the request"); if(JsonNode.class.isAssignableFrom(entityClass)) return (T) mapper.readTree(data); return mapper.readValue(data, entityClass); } catch(JsonProcessingException e) { throw new ClientDataError("invalid json in client request. "+e.getMessage(), e); } catch (IOException e) { throw new RuntimeException("should not occur", e); } }
@SuppressWarnings({ "rawtypes", "unchecked" }) public Map<String, String> formMap(Method method, List<String> pathParamNames, Map<String, Object> redirectArgs) { if(pathParamNames.size() != redirectArgs.size()) throw new IllegalReturnValueException("The Redirect object returned from method='"+method+"' has the wrong number of arguments. args.size="+redirectArgs.size()+" should be size="+pathParamNames.size()); Map<String, String> nameToValue = new HashMap<>(); for(int i = 0; i < pathParamNames.size(); i++) { String key = pathParamNames.get(i); Object value = redirectArgs.get(key); //value can't be null on redirect if(value == null) throw new IllegalArgumentException("Controller did not set key='"+key+"' or passed in null" + " for '"+key+"' and this is not allowed as you end up with the word 'null' in your url"); ObjectStringConverter function = translator.getConverterFor(value); nameToValue.put(key, function.objectToString(value)); } return nameToValue; } }
/** * This has to be above LoginFilter so LoginFilter can flash the multiPartParams so edits exist through * a login!! * */ private void tokenCheck(Route route, RequestContext ctx, BodyContentBinder bodyContentBinder) { RouterRequest req = ctx.getRequest(); if(req.multiPartFields.size() == 0) return; if(config.isTokenCheckOn() && route.isCheckSecureToken()) { String token = ctx.getSession().get(SessionImpl.SECURE_TOKEN_KEY); List<String> formToken = req.multiPartFields.get(RequestContext.SECURE_TOKEN_FORM_NAME); if(formToken == null) throw new BadRequestException("missing form token(or route added without setting checkToken variable to false)" + "...someone posting form without getting it first(hacker or otherwise) OR " + "you are not using the #{form}# tag or the #{secureToken}# tag to secure your forms"); else if(!token.equals(formToken.get(0))) throw new BadRequestException("bad form token...someone posting form with invalid token(hacker or otherwise)"); } }
private RouterCookie scopeToCookie(CookieScopeImpl scopeData) throws UnsupportedEncodingException { Map<String, String> mapData = scopeData.getMapData(); RouterCookie cookie = createBase(scopeData.getName(), null); StringBuilder data = translateValuesToCookieFormat(mapData); String value = data.toString(); if(scopeData instanceof SecureCookie) { SecretKeyInfo key = config.getSecretKey(); String sign = security.sign(key, value); cookie.value = VERSION+"-"+sign+":"+value; } else { cookie.value = VERSION+":"+value; } if(cookie.value.length() > 4050) throw new CookieTooLargeException("Your webserver has put too many things into the session cookie and" + " browser will end up ignoring the cookie so we exception here to let you " + "know. Length of JUST the value(not whole cookie)="+cookie.value.length()+"\ncookie value="+cookie.value); return cookie; }
String hash = security.sign(config.getSecretKey(), keyValuePairs); if(!hash.equals(expectedHash)) throw new BadCookieException("hashes don't match...This occurs if secret key" + " was switched, or loaded different webapp on same port or someone" + " created an invalid cookie and sent to your webserver", data.getName()); throw new BadCookieException("versions don't match...This occurs if secret key" + " was switched, or loaded different webapp on same port or someone" + " created an invalid cookie and sent to your webserver", data.getName());
reason = e.getMessage();
public CompletableFuture<Render> renderToken(String token) { Current.getContext().addModifyResponse((http2Response) -> modifyResponse(http2Response)); CompletableFuture<Map<String, String>> future = storage.read(InstallSslCertPlugin.PLUGIN_PROPERTIES_KEY); return future.thenApply((props) -> { String result = props.get(token); log.info("token="+token+" value="+result); if(result == null) throw new NotFoundException(); int index = result.indexOf("---"); String authContent = result.substring(0, index); //check token exists in database return Actions.renderThis("authContent", authContent); }); }
private RouteMeta getByName(String name) { if(duplicateNames.contains(name)) { Set<RouteId> keySet = routeIdToRoute.keySet(); String routes = ""; for(RouteId id : keySet) { if(name.equals(id.name())) routes += "\nroute="+id.getClass(); } throw new RouteNotFoundException("There is more than one route matching the name. Qualify it with the class like XXXRouteId." +name+". Same names are found in these enum classes="+routes); } RouteMeta routeMeta = routeNameToRoute.get(name); if(routeMeta == null) throw new RouteNotFoundException("route="+name+" not found."); return routeMeta; }
throw new IllegalReturnValueException("Route="+id+" returned from method='"+method+"' was not added in the RouterModules"); else if(!nextRequestMeta.getRoute().matchesMethod(HttpMethod.GET)) throw new IllegalReturnValueException("method='"+method+"' is trying to redirect to routeid="+id+" but that route is not a GET method route and must be"); List<String> argNames = route.getPathParamNames(); if(keySet.size() != argNames.size()) { throw new IllegalReturnValueException("Method='"+method+"' returns a Redirect action with wrong number of arguments. args="+keySet.size()+" when it should be size="+argNames.size());
private void checkForBadNullToPrimitiveConversion(RouterRequest req, ParamNode valuesToUse, Meta fieldMeta, Method method) { Class<?> paramTypeToCreate2 = fieldMeta.getFieldClass(); if(paramTypeToCreate2.isPrimitive()) { if(valuesToUse == null) { String s = "The method='"+method+"' requires that "+fieldMeta+" be of type=" +paramTypeToCreate2+" but the request did not contain any value in query params, path " + "params nor multi-part form fields with a value and we can't convert null to a primitive"; throw new DataMismatchException(s); } } }
@SuppressWarnings("rawtypes") private Object convert(RouterRequest req, Method method, ParamNode valuesToUse, Meta fieldMeta, ObjectStringConverter converter, Validation validator) { Class<?> paramTypeToCreate = fieldMeta.getFieldClass(); if(fieldMeta instanceof ParamMeta) { //for params only not fields as with fields, we just don't set the field and skip it...before we call a method, //we MUST have a value to set checkForBadNullToPrimitiveConversion(req, valuesToUse, fieldMeta, method); } if(valuesToUse == null) return null; if(!(valuesToUse instanceof ValueNode)) throw new IllegalArgumentException("method takes param type="+paramTypeToCreate+" but complex structure found"); ValueNode node = (ValueNode) valuesToUse; String value = node.getValue(); try { return converter.stringToObject(value); } catch(Exception e) { if(node.getFrom() == FromEnum.FORM_MULTIPART) { validator.addError(node.getFullKeyName(), "Could not convert value"); return null; } else //This should be a 404 in production if the url is bad... throw new NotFoundException("The method='"+method+"' requires that the parameter or field '"+fieldMeta+"' be of type=" +paramTypeToCreate+" but the request contained a value that could not be converted="+value); } }
private RouteMeta getByClassAndName(String name) { if(duplicateClassAndNames.contains(name)) { Set<RouteId> keySet = routeIdToRoute.keySet(); String routes = ""; for(RouteId id : keySet) { String potentialName = id.getClass().getSimpleName()+"."+id.name(); if(name.equals(potentialName)) routes += "\nroute="+id.getClass().getName()+"."+id.name(); } throw new RouteNotFoundException("There is more than one route matching the class and name. Qualify it with the package like org.web." +name+". These are the conflicting ids which is why you need to be more specific="+routes); } RouteMeta routeMeta = classAndNameToRoute.get(name); if(routeMeta == null) throw new RouteNotFoundException("route="+name+" not found"); return routeMeta; }
throw new IllegalReturnValueException("Controller method='"+method+"' MUST follow the PRG " + "pattern(https://en.wikipedia.org/wiki/Post/Redirect/Get) so " + "users don't have a poor experience using your website with the browser back button. "
public String convertToUrl(String routeId, Map<String, String> args, boolean isValidating) { RouteMeta routeMeta = get(routeId); Route route = routeMeta.getRoute(); String urlPath = route.getFullPath(); List<String> pathParamNames = route.getPathParamNames(); for(String param : pathParamNames) { String val = args.get(param); if(val == null) { String strArgs = ""; for(Entry<String, String> entry : args.entrySet()) { boolean equals = entry.getKey().equals(param); strArgs = " ARG:'"+entry.getKey()+"'='"+entry.getValue()+"' equals="+equals+"\n"; } throw new RouteNotFoundException("missing argument. param="+param+" is required" + " to exist(and cannot be null as well). route="+routeId+" args="+strArgs); } String encodedVal = urlEncode(val); urlPath = urlPath.replace("{"+param+"}", encodedVal); } if(isValidating) return urlPath; return createUrl(route, urlPath); }