Is there a reliable way to separately extract GET and POST parameters using a HttpServletRequest?
That is, differentiate parameters that were sent in the query string (GET) to parameters that were sent in the request body (POST), assuming Content-Type: application/x-www-form-urlencoded.
Example
POST /path HTTP/1.1
Host: test.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
first_name=posted_foo&last_name=posted_bar
I would like to end up with two variables, one containing the values from the URL and one containing the values from the request body:
get = {"first_name": "foo", "last_name": "bar"}
post = {"first_name": "posted_foo", "last_name": "posted_bar"}
The only methods I seem to be able to extract these parameters are the getParameter* methods.
HttpServletRequest.getParameter: Returns a single string and tends to be the value provided in the URL (GET).
HttpServletRequest.getParameterValues: Returns an array of strings containing all of the values provided in the query string and request body. Those passed via the query string tend to appear first. However, if only one value is present in the returns array of strings, it cannot be reliably determined whether the value came from the query string or the request body.
To illustrate, using PHP these values are provided through the $_GET and $_POST superglobals.
The query string is trivial to parse, thus gives you the URI query param names, while the getParameterNames() gives you the whole set.
Split the query string by '&', then subsplit each token by '='.
For each key and value, perform the URLDecoder.decode(). That's all.
Toss all such keys in a set. If the param is in the uri query set it a good chance it's only there. If you must find if it is also in the post, actually, post form-encoded data is also coded like that, but that post is consumed so it's too late. Besides, the post could also be a multipart encoding which is non-trivial decode.
In the end, it's odd that you need this distinction. Can you explain for what purpose you seek this distinction?
Related
I am trying to make a Java web server that will compare the if-modified-since with the file's last modified.
However, I don't know how to get the if-modified-since header from the client and do the comparison.
I wouldn't jump right into trying to handle a particular header. If you're writing a web server from scratch then you should write a generic HTTP parser that can handle every part of an HTTP request:
Request line
Request method (GET, POST, etc.)
URL
HTTP version
Zero or more headers of the form Name: Value
A blank line
Message body
You could, for instance, build up a class like:
class HttpRequest {
String method;
URL url;
String httpVersion;
Map<String, String> headers;
byte[] body;
}
Since header names are case insensitive I'd suggest using map with String.CASE_INSENSITIVE_ORDER.
Once you can parse all headers than looking for a particular header will be a simple task. If you had the class above it'd be as easy as looking up headers.get("If-Modified-Since").
I am trying to connect to a REST API (Not my own so I can't fix their issues) but when I send a GET request, Rest Assured is reprocessing my URI causing the call to fail.
Here is the code to build the request:
Call rest = new Call("https://rest.test.com"); // Custom class to simplify REST calls.
JSONObject searchCriteria = new JSONObject();
searchCriteria.put("textSearchType", "SEARCHNAME");
searchCriteria.put("textSearchString", "joe blow");
String header = "Lead Inline Quick Search";
StringBuilder resource = new StringBuilder("/api/v1/search?");
resource.append("searchCriteria=")
.append(URLEncoder.encode(searchCriteria.toString()))
.append("&header=")
.append(URLEncoder.encode(header));
System.out.println("REST call: " + resource.toString());
rest.get(resource.toString(), 200); // Perform a get on the query, expect a 200 response
When I look at the output, the request is correct:
REST call: /api/v1/search?searchCriteria=%7B%22textSearchString%22%3A%22joe+blow%22%2C%22textSearchType%22%3A%22SEARCHNAME%22%7D&header=Lead+Inline+Quick+Search
However when I look at the debug for Rest Assured, it reprocesses the request causing the call to fail:
Request method: GET
Request URI: https://rest.test.com/api/v1/search?searchCriteria=%257B%2522textSearchString%2522%253A%2522joe%2Bblow%2522%252C%2522textSearchType%2522%253A%2522SEARCHNAME%2522%257D&header=Lead%2BInline%2BQuick%2BSearch
Note:
'{' is correctly converted to '%7B' from the Net encoding and looks right in the resource, but Rest Assured then further converts all the '%' to '%25' making the json invalid ({ becomes %257B).
The '+' in the header is converted to '%20' for some reason. While technically the same, there is no reason to "fix" it.
If I don't encode the values when building the resource, the get call fails because it sees the spaces.
IllegalArgumentException-Invalid number of path parameters. Expected 1, was 0. Undefined path parameters are: "textSearchString":"joe blow","textSearchType":"SEARCHNAME".
So what is the proper way to encode the values? Or get Rest Assured not to monkey with the string it's sent?
The comment from #Hypino put me on the right track.
Adding .urlEncodingEnabled(false) to the .given() did not change the results (call was still double processed). But adding .setUrlEncodingEnabled(false) to the RequestSpecBuilder() gave the correct results.
private RequestSpecBuilder build = new RequestSpecBuilder().setUrlEncodingEnabled(false);
The logged call and the actual call are now the same:
REST call: /api/v1/search?searchCriteria=%7B%22textSearchString%22%3A%22joe+blow%22%2C%22textSearchType%22%3A%22SEARCHNAME%22%7D&header=Lead+Inline+Quick+Search
Request method: GET
Request URI: https://rest.test.com/api/v1/search?searchCriteria=%7B%22textSearchString%22%3A%22joe+blow%22%2C%22textSearchType%22%3A%22SEARCHNAME%22%7D&header=Lead+Inline+Quick+Search
I'm currently developing a Servlet that runs under Glassfish 4.
I implemented the doPost() method and I need to ensure that the parameters are passed using the POST body, and not in the query string.
I wrote a test implementation to check it:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
response.getOutputStream().print(name);
}
If I call my page with POST with this url:
http://localhost:8080/myservlet/testservlet
and pass name=Nico into the post body, the value Nico is returned, and it's okay.
Now if I call it this way:
http://localhost:8080/myservlet/testservlet?name=Robert
and I still pass name=Nico in the POST body, Robert is returned, and the name=Nico is ignored.
I just would like to avoid parameters to be passed in the URL.
Is there a way to explicitly retrieve parameters from the POST body instead of body + query string?
Check the javadoc for the getParameter method:
https://tomcat.apache.org/tomcat-7.0-doc/servletapi/javax/servlet/ServletRequest.html#getParameter%28java.lang.String%29
Like it is stated, you are sending 2 parameters on the request with the same name, one from the query string and another on the body.
Now it is up to you to either validate that no parameter is coming from the query string or read directly values from the request body.
In most cases, you can read both of them using getParameterValues, the first one is query string and the second one is post body. Now you can decide which one to use.
String[] lines = request.getParameterValues("name");
Did you check what request.getAttribute() returns?
Anyway you can't avoid that people will try to send you evil data, either in the url or by tinkering with the post-request.
So when you work with input from a website, always imagine a hacker sitting on the other side and sending you evil content in your parameters, like sql-injections. So you need a good validation to only let good content through to your database.
Because it's not your problem if a user enters his username as a parameter in the url. Let him have the fun, if he prefers this way over the input-field. The hackers are the problem.
I think it is a problem of front end code, instead of servlet. Any post request submission from UI should strip query string.
I have an iframe and a textbox(to enter required url) in my main page, so when user enters required URL I load requested page to iframe.
I am using HttpServlet to handle get requests through doGet. I need to distinguish the requested content type, because if it is a file(img or script) I just read it and return, but if it is an html page, I make some modifications.
I tried to use request.getContentType() inside doGet but it returns null. So is there any way to do this? Thank You
HttpServletRequest#getContentType() returns the value of the Content-Type header if there is one.
You need to specify it when sending the request. You can use Javascript to do this.
Alternatively, but not ideally, you could use a query string parameter to hint at content type.
That's for getting the content type of the request body.
If you want to specify what content the response should have, you need to specify the Accept header with an appropriate media type.
You can alternatively, do URL extension matching. For example, www.host.com/some/path.xml would return XML.
The request.getContentType() method will only return a value if your request body contains data. Since it's a GET it does not contain any body. If you have any data it's either part of the URL or in a query-string attached to the URL. It's pointless to declare Content-type in GET requests, so there is no header to read.
You have to look for the data that you need in your request URL.
If it's a URL generated by a link or image, then get the name and extension from the URL.
It it's generated by a script, it might have that information elsewhere, such as in some variable in the query string (?file-name=xyz&file-type=png for example) or in extra path information (/servlet/xyz/jpeg for example). It depends on how your client is requesting the data.
Do you want to know content type of request, mabye you don't know what for you requests check your URL. If your request contain no data you can request.getContentType should return null value. You can do it on response not request. Mabye you can pass parameter do define what response do you want. I suppouse you have to check response type to determine behaviour of your application depends on the response type not request. Simple GET request only wait for response. And based on that response do some actions.
request.getParameter() to retrieve items sent by POST and/or GET.
String name = request.getParameter("name");
But how can we distinguish between these two cases? In fact, if I send both a post and get with the same name, what getParameter returns me?
An HTTP request can only have one method associated. So in your case, your request is either a GET request or a POST request, but not both. Note that other HTTP methods than GET or POST exists (OPTIONS, PUT, DELETE, ...).
If you want to know which method was used in your current request, you can use request.getMethod().
request.getParameter("name"); will return the value associated with HTML/JSP element having id="name"in both GET and POST cases.
If you want to check whether the request was GET or POST you can use request.getMethod();
You can use only one at a time GET or POST. And your statement retrieve value whose name/id="name". You can check method by request.getMethod(); Also GET is used for limited data around 2 kb and POST for unlimited data to be retrieved.