SpringBoot Path variable problem with slash - java

I have some problem with slashes in variable thats hould be send in url.
For example id could be like this:
ID: /gfdge1/DkxA8P+jYw43
URL: localhost:8080/find-user//gfdge1/DkxA8P+jYw43
"error": "Internal Server Error",
"exception": "org.springframework.security.web.firewall.RequestRejectedException",
"message": "The request was rejected because the URL was not normalized.",
because of this slash on first place it make problem
Before that i had problems with these slash in middle of ID but I've solved that with this code:
#RequestMapping(name = "Get user data by ID", value = "/find-user/{userId}/**", method = RequestMethod.GET)
#ResponseBody
public User getUserData(#PathVariable String userId, HttpServletRequest request) {
final String path =
request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
final String bestMatchingPattern =
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
String arguments = new AntPathMatcher().extractPathWithinPattern(bestMatchingPattern, path);
String id="";
if (null != arguments && !arguments.isEmpty()) {
id = userId + '/' + arguments;
} else {
id = userId;
}
return userService.getUserData(id);
}
but this doesn't work for this case when slash is on first place.
I've also try to user RequestParam instead of PathVariable, but it have problems with some special characters for example when I user RequestParam it replace '+' with empty space,...
Does anyone can help me how to solve this problem?

Its an inherent issue with using Strings as path variables, it's not an issue with your code but how the HTTP request is interpreted so you can't do anything in your code to make this work.
You do have some options though:
Ensure the values you use cannot be created with special characters such as "/"
Avoid using Strings in path variables completely.
I lean more towards 2 as maintaining 1 for all possible problem characters/strings is pretty messy and unnecessary.
To do 2 correctly you should consider having all your REST getters finding their related entities by a numeric ID only e.g.
localhost:8080/find-user/3
If you need to add additional search parameters e.g. username in your case then you should use something like QueryDSL to create a predicate of search parameters which are passed as query parameters instead of path variables e.g.:
localhost:8080/find-user?username=/gfdge1/DkxA8P+jYw43

Related

Invalid Character Constant at ( 'node-fetch')

so this is my code:
My code is saying that on the 2nd line (String fetch.....) there are 2 Invalid character constants & I cant figure out how to fix this
=====================================================
public static void api() {
String fetch = require('node-fetch');
let API_FILE = require('./API_KEY.json');
let API_KEY = API_FILE["API_KEY"] // API key location
String playername = "Username"; // Players Username
String playerUUID = "UUID of said username"; // Players UUID
fetch('https://api.hypixel.net/player?key=$[API_KEY]&name=$[playername]') // Retrieves data from <-- website
.then(response => response.json())
.then(data {
console.log(data)
})
.catch(error => console.log("Network Error", error))) // Informs me if anything went wrong
}
Error #1
In java, you can only create a String by putting it into " signs.
You can put a single character in ' signs to create a char.
A String, e.g. "Test" consists of multiple chars, e.g. 'T' & 'e' & 's' & 't', so it is basically a char[], which you cannot modify.
Error #2
The keyword let is not supported in java. You need to replace it with the specific type of the object you want to store. If you don't want to do that, var works in newer versions.
Error #3
Unlike in javascript, you cannot have Strings as array indices. If you want to do that anyway, you'll have to use a Map:
Map<String, Something> map = new HashMap<>();
map.put("Test", new Something());
map.get("Test") //returns the new Something instance
But I don't think you want that here (API_FILE?)
Error #4
Your server request is a javascript request, which has nothing to do with java. This is a tutorial about how to make server requests in java.
Why do you want to log player data from Hypixel?

#PathVariable with slashes in middle of #GetMapping, #DeleteMapping URL

I cant solve this problem
(#PathVariable with slashes in middle of #GetMapping, #DeleteMapping URL) help me please!
URL ex : aaa/test/111/l2323:sdfsd:23423423/bbb
- test/111/l2323:sdfsd:23423423 : string variable with slashes
- bbb : another variable
#GetMapping("aaa/**")
public #ResponseBody List<Dto> getAAA(HttpServletRequest request) {
...
}
#DeleteMapping("aaa/**/{bbb}")
public void deleteTest(HttpServletRequest request,
#PathVariable("bbb") String bbb) {
...
}
#GetMapping("aaa/**/{bbb}")
public Dto getTest(HttpServletRequest request,
#PathVariable("bbb") String bbb) {
...
}
private String extractSlashVariable(HttpServletRequest request) {
String path = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String bestMatchPattern = (String) request.getAttribute(
HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
}..
how can I handle this problems?
The above codes are not working...
Help me please Thank you!!
A principled answer would be - you can't. URLs exist with the assumption of a structure - each part being separated by a slash. Having a "variable" containing slashes in your url is an invalid thing to take in as a rule, a variable can't span multiple levels of the url. If a path parameter can contain problematic characters like slashes they need to be url-encoded (%2F I believe is the encoded version of /).
If you really want to just hack it to work - if you do set the ant matching strategy to ant_path_matcher (that allows matching paths like /**/test) like the error message suggests it might allow you to parse it. You will get ambiguity error between your two GETs, that will be impossible, but having just one of them and the delete miiiight work. To do that just add spring.mvc.pathmatch.matching-strategy=ant_path_matcher to your application.properties.

semicolon in the restful service URL truncate the characters after it

I have the below code as my restful service operation.
#GET
#UnitOfWork
#Timed(name = "get-requests")
#Path("/{referenceId}")
public Response get(#Auth #ApiParam(access = "internal") UserPrincipal user,
#ApiParam(name = "id", value = "reference ID", required = true)
#PathParam("referenceId") String id) {
return Response.ok(id).build();
}
However, I noticed if I pass in m1234;5678, I get only m1234 returned. I tried #Path("/{referenceId:.*}"), but it doesn't work.
I also tried use #Encode at the top of the method to make sure the url is not decoded and then try to replace %3B with ";" in the code. But it seems not working also.
Please note that I cannot use Spring framework. Thanks.
The ; denotes a matrix parameter. Use #MatrixParam to get its value.
See also the answers to this question: URL matrix parameters vs. request parameters
Edit: The key of the matrix parameter would be 5678, the value would be null.
There is a way to get achieve what you want by using PathSegment as the type of the parameter instead of String:
#PathParam("referenceId) PathSegment id
In the body of the method, you can use
String idValue = id.getPath();
to get m1234;5678.

Can string and variable name be different in queryparam annotation in java?

Here is a scenario.
Case1: (#QueryParam("username") String username)
URL: example?username=yourname
Case2: (#QueryParam("username") String name)
URL: example?username=yourname
In these 2 cases which is correct way of using QueryParam.
When I use Case1, it works, yourname is printed. But when I use Case2, null is printed.
I want to implement Case 2 because of following some coding standards. Means I do not want to change the variable name (which is "String name"). But in URL I have to use "username".
Is there any way of using Case2 scenario for QueryParam.
Adding code(1st edit)
Here is the code which I replicated the issue that I am facing
#RequestMapping (value = "/username1", method = RequestMethod.GET)
#ResponseBody
public Response username1(#QueryParam("username") String username) {
System.out.println("Username1 is ==> " + username);
return Response.ok(username).build();
}
#RequestMapping (value = "/username2", method = RequestMethod.GET)
#ResponseBody
public Response username2(#QueryParam("username") String name) {
System.out.println("Username2 is ==> " + name);
return Response.ok(name).build();
}
/username1?username=yourname
Output: Username1 is ==> yourname
/username2?username=yourname
Output: Username2 is ==> null
Thank you
Yes, you're doing something wrong: you're using QueryParam, which is a JAX-RS annotation, in a Spring-MVC application.
The equivalent Spring annotation is RequestParam. JAX-RS and Spring MVC are two different things. You can't just use the annotations of one in the other.

Spring REST Controller understanding arrays of strings when having special characters like blank spaces or commas

I am trying to write a Spring REST Controller getting an array of strings as input parameter of a HTTP GET request.
The problem arises when in the GET request, in some of the strings of the array, I use special characters like commas ,, blank spaces or forward slash /, no matter if I URL encode the query part of the URL HTTP GET request.
That means that the string "1/4 cup ricotta, yogurt" (edit which needs to be considered as a unique ingredient contained as a string element of the input array) in either this format:
http://127.0.0.1:8080/[...]/parseThis?[...]&ingredients=1/4 cup ricotta, yogurt
This format (please note the blank spaces encoded as + plus, rather than the hex code):
http://127.0.0.1:8080/[...]/parseThis?[...]&ingredients=1%2F4+cup+ricotta%2C+yogurt
Or this format (please note the blank space encoded as hex code %20):
http://127.0.0.1:8080/[...]/parseThis?[...]&ingredients=1%2F4%20cup%20ricotta%2C%20yogurt
is not rendered properly.
The system does not recognize the input string as one single element of the array.
In the 2nd and 3rd case the system splits the input string on the comma and returns an array of 2 elements rather than 1 element. I am expecting 1 element here.
The relevant code for the controller is:
#RequestMapping(
value = "/parseThis",
params = {
"language",
"ingredients"
}, method = RequestMethod.GET, headers = HttpHeaders.ACCEPT + "=" + MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public HttpEntity<CustomOutputObject> parseThis(
#RequestParam String language,
#RequestParam String[] ingredients){
try {
CustomOutputObject responseFullData = parsingService.parseThis(ingredients, language);
return new ResponseEntity<>(responseFullData, HttpStatus.OK);
} catch (Exception e) {
// TODO
}
}
I need to perform HTTP GET request against this Spring controller, that's a requirement (so no HTTP POST can be used here).
Edit 1:
If I add HttpServletRequest request to the signature of the method in the controller, then I add a log statement like log.debug("The query string is: '" + request.getQueryString() + "'"); then I am seeing in the log a line like The query string is: '&language=en&ingredients=1%2F4+cup+ricotta%2C+yogurt' (So still URL encoded).
Edit 2:
On the other hand if I add WebRequest request to the signature of the method, the the log as log.debug("The query string is: '" + request.getParameter("ingredients") + "'"); then I am getting a string in the log as The query string is: '1/4 cup ricotta, yogurt' (So URL decoded).
I am using Apache Tomcat as a server.
Is there any filter or something I need to add/review to the Spring/webapp configuration files?
Edit 3:
The main problem is in the interpretation of a comma:
#ResponseBody
#RequestMapping(value="test", method=RequestMethod.GET)
public String renderTest(#RequestParam("test") String[] test) {
return test.length + ": " + Arrays.toString(test);
// /app/test?test=foo,bar => 2: [foo, bar]
// /app/test?test=foo,bar&test=baz => 2: [foo,bar, baz]
}
Can this behavior be prevented?
The path of a request parameter to your method argument goes through parameter value extraction and then parameter value conversion. Now what happens is:
Extraction:
The parameter is extracted as a single String value. This is probably to allow simple attributes to be passed as simple string values for later value conversion.
Conversion:
Spring uses ConversionService for the value conversion. In its default setup StringToArrayConverter is used, which unfortunately handles the string as comma delimited list.
What to do:
You are pretty much screwed with the way Spring handles single valued request parameters. So I would do the binding manually:
// Method annotations
public HttpEntity<CustomOutputObject> handlerMethod(WebRequest request) {
String[] ingredients = request.getParameterValues("ingredients");
// Do other stuff
}
You can also check what Spring guys have to say about this.. and the related SO question.
Well, you could register a custom conversion service (from this SO answer), but that seems like a lot of work. :) If it were me, I would ignore the declaration the #RequestParam in the method signature and parse the value using the incoming request object.
May I suggest you try the following format:
ingredients=egg&ingredients=milk&ingredients=butter
Appending &ingredients to the end will handle the case where the array only has a single value.
ingredients=egg&ingredients=milk&ingredients=butter&ingredients
ingredients=milk,skimmed&ingredients
The extra entry would need to be removed from the array, using a List<String> would make this easier.
Alternatively if you are trying to implement a REST controller to pipe straight into a database with spring-data-jpa, you should take a look at spring-data-rest. Here is an example.
You basically annotate your repository with #RepositoryRestResource and spring does the rest :)
A solution from here
public String get(WebRequest req) {
String[] ingredients = req.getParameterValues("ingredients");
for(String ingredient:ingredients ) {
System.out.println(ingredient);
}
...
}
This works for the case when you have a single ingredient containing commas

Categories