Passing a very long URL to a HTTPServletRequest - java

I want to pass a long series of request parameters (over 2000 characters in total) from one .jsp to another (via a URL), and make it seem to the receiving HTTPServletRequest as if it received the request parameters normally.
I cannot simply pass the URL normally as IE11 is truncating the URL at about 2000 characters (see What is the maximum length of a URL in different browsers?) so I need to have some kind of workaround.
It is trivial to save the url in the ClientSession with a key in one .jsp
public String addValue(String aString) {
String key=""+UUID.randomUUID();
mapValues.put(key, aString);
return key;
}
and then retrieve it in the other .jsp
public String getValue(String key) {
return mapValues.get(key);
}
However the other .jsp needs a HTTPServletRequest and not a string
I.e. I need to be able to do
public MyPosition(HttpServletRequest request) {
this.id= (String)request.getParameter("ID");
Is there anyway of doing this by converting the retrieved url to a HTTPServletRequest?
I know that I could rewrite MyPosition to take a string and extract the data from there directly, but I would much rather not touch the very lengthy, legacy code.
If I could do setParameter on the request, then this would be a solution. But such an option is not available (see HttpServletRequest - SetParameter)

The only way to modify an HttpServletRequest is to wrap it.

It sounds like you want to make a standard POST request instead of what sounds like a GET request.

I tried both #dimplex's and #Deadron's solutions, which I think should both work, but didn't manage to implement either in the short time frame I had available.
I ended up replacing the HTTPServletRequest request parameter in the MyPosition function with String urlKey and adding the following line inside the function
RequestStr request=new RequestStr(cSession,urlKey);
now my existing code did not need to be changed at all, and request.getParameter("paramName") would call my function below.
public class RequestStr {
String url = "";
public RequestStr(ClientSession cSession, String urlKey) {
super();
this.url = cSession.getValue(urlKey);
}
public String getParameter(String aParam) {
int i = url.indexOf("?" + aParam + "=");
if (i == -1) {
i = url.indexOf("&" + aParam + "=");
}
if (i == -1) {
return null;
} else {
int j = url.indexOf("&", i + 1);
if (j == -1) {
return url.substring(i + aParam.length() + 2);
} else {
return url.substring(i + aParam.length() + 2, j);
}
}
}
}
So all I needed to do was to save the very long URL in the session in a map with key urlKey and then in the request just passed this urlKey, and then I could retrieve the long URL via the urlKey and then decode it via my RequestStr class

Related

Obtain specific part of a string with JSON Format java

I have a question on how would be the best way to get the information from a string but that has JSON format.
{
"internal_id":"1234",
"moreInformation":"Failed authentication for user."
}
In this case, I want to get the value of "internal_id" and I already did, with subtring, lastIndexOf and indexOf
public static String returnInternalCode(String json){
String internalCode = json.substring(json.lastIndexOf("\"internal_id\":\"") + "\"internal_id\":\"".length(), json.length() - 1);
if (json.lastIndexOf("\"internal_id\":\"") == -1) return null;
return internalCode.substring(0, internalCode.indexOf("\""));
}
I also tried several JSONs with order changes that don't have the data and it also worked. I leave the full class of tests I did:
public class Test {
public static void main(String[] args) {
// Original JSON
String json = "{\"internal_id\":\"999999\",\"moreInformation\":\"Failed authentication for user, 1 authentication attempt remaining.\"}";
// Other JSON order
String json2 = "{\"moreInformation\":\"Failed authentication for user. Invalid response.\", \"moreInformation2\":\"Failed authentication for user. \", \"internal_id\":\"45678\"}";
// JSON without the internal_id
String json3 = "{\"moreInformation\":\"Failed authentication for user. Invalid response.\"}";
// JSON without moreInformation
String json4 = "{\"internal_id\":\"999999\"}";
System.out.println("JSON: ".concat(json4));
System.out.println("internalId: " + returnInternalId(json4));
System.out.println("moreInformation: " + returnMoreInformation(json4));
}
public static String returnInternalId(String json){
String internalCode = json.substring(json.lastIndexOf("\"internal_id\":\"") + "\"internal_id\":\"".length(), json.length());
if (json.lastIndexOf("\"internal_id\":\"") == -1) return null;
return internalCode.substring(0, internalCode.indexOf("\""));
}
public static String returnMoreInformation(String json){
String moreInformation = (json.substring(json.lastIndexOf("\"moreInformation\":\"") + "\"moreInformation\":\"".length(), json.length()));
if (json.lastIndexOf("\"moreInformation\":\"") == -1) return null;
return moreInformation.substring(0, moreInformation.indexOf("\""));
}
}
I would like to know if there are better ways to do what I did, such as with StringBuilder or StringBuffer and also to find out which way uses less memory or is faster to run, how do I know that? How long does it take to execute a method?
Thank you very much!
You can extract the values this way; Using Simple-json library
JSONObject jobj = (JSONObject) parser.parse(yourJsonString); // Pass the Json formatted String
String internal_id = (String) jobj.get("internal_id"); // Extract the value from your key
System.out.println(internal_id); // 1234

Java - Replace host in url?

In java, I'd like to replace the Host part of an url with a new Host, where both the host and url are supplied as a string.
This should take into account the fact that the host could have a port in it, as defined in the RFC
So for example, given the following inputs
url: http://localhost/me/out?it=5
host: myserver:20000
I should get the following output from a function that did this correctly
http://myserver:20000/me/out?it=5
Does anyone know of any libraries or routines that do Host replacement in an url correctly?
EDIT: For my use case, I want my host replacement to match what a java servlet would respond with. I tried this out by running a local java web server, and then tested it using curl -H 'Host:superduper.com:80' 'http://localhost:8000/testurl' and having that endpoint simply return the url from request.getRequestURL().toString(), where request is a HttpServletRequest. It returned http://superduper.com/testurl, so it removed the default port for http, so that's what I'm striving for as well.
The Spring Framework provides the UriComponentsBuilder. You can use it like this:
import org.springframework.web.util.UriComponentsBuilder;
String initialUri = "http://localhost/me/out?it=5";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(initialUri);
String modifiedUri = builder.host("myserver").port("20000").toUriString();
System.out.println(modifiedUri);
// ==> http://myserver:20000/me/out?it=5
Here you need to provide hostname and port in separate calls to get right encoding.
You were right to use java.net.URI. The host and port (and user/password, if they exist) are collectively known as the authority component of the URI:
public static String replaceHostInUrl(String originalURL,
String newAuthority)
throws URISyntaxException {
URI uri = new URI(originalURL);
uri = new URI(uri.getScheme().toLowerCase(Locale.US), newAuthority,
uri.getPath(), uri.getQuery(), uri.getFragment());
return uri.toString();
}
(A URI’s scheme is required to be lowercase, so while the above code can be said not to perfectly preserve all of the original URL’s non-authority parts, an uppercase scheme was never actually legal in the first place. And, of course, it won’t affect the functionality of the URL connections.)
Note that some of your tests are in error. For instance:
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com:4300/me/out?it=5","super:443"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://www.test.com:4300/me/out?it=5","super:80"));
Although https://super/me/out?it=5 is functionally identical to https://super:443/me/out?it=5 (since the default port for https is 443), if you specify an explicit port in a URI, then the URI has a port specified in its authority and that’s how it should stay.
Update:
If you want an explicit but unnecessary port number to be stripped, you can use URL.getDefaultPort() to check for it:
public static String replaceHostInUrl(String originalURL,
String newAuthority)
throws URISyntaxException,
MalformedURLException {
URI uri = new URI(originalURL);
uri = new URI(uri.getScheme().toLowerCase(Locale.US), newAuthority,
uri.getPath(), uri.getQuery(), uri.getFragment());
int port = uri.getPort();
if (port > 0 && port == uri.toURL().getDefaultPort()) {
uri = new URI(uri.getScheme(), uri.getUserInfo(),
uri.getHost(), -1, uri.getPath(),
uri.getQuery(), uri.getFragment());
}
return uri.toString();
}
I quickly tried using java.net.URI, javax.ws.rs.core.UriBuilder, and org.apache.http.client.utils.URIBuilder, and none of them seemed to get the idea of a host header possibly including a port, so they all needed some extra logic from what I could see to make it happen correctly, without the port being "doubled up" at times, and not replaced correctly at other times.
Since java.net.URL doesnt require any extra libs, I used it. I do know that if I was using URL.equals somewhere, that could be a problem as it does DNS lookups possibly, but I'm not so I think it's good, as this covers my use cases, as displayed by the pseudo unit test.
I put together this way of doing it, which you can test it out online here at repl.it !
import java.net.URL;
import java.net.MalformedURLException;
class Main
{
public static void main(String[] args)
{
testReplaceHostInUrl();
}
public static void testReplaceHostInUrl()
{
assertEquals("http://myserver:20000/me/out?it=5", replaceHostInUrl("http://localhost/me/out?it=5","myserver:20000"));
assertEquals("http://myserver:20000/me/out?it=5", replaceHostInUrl("http://localhost:19000/me/out?it=5","myserver:20000"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://localhost:19000/me/out?it=5","super"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://www.test.com/me/out?it=5","super"));
assertEquals("https://myserver:20000/me/out?it=5", replaceHostInUrl("https://localhost/me/out?it=5","myserver:20000"));
assertEquals("https://myserver:20000/me/out?it=5", replaceHostInUrl("https://localhost:19000/me/out?it=5","myserver:20000"));
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com/me/out?it=5","super"));
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com:4300/me/out?it=5","super"));
assertEquals("https://super/me/out?it=5", replaceHostInUrl("https://www.test.com:4300/me/out?it=5","super:443"));
assertEquals("http://super/me/out?it=5", replaceHostInUrl("http://www.test.com:4300/me/out?it=5","super:80"));
assertEquals("http://super:8080/me/out?it=5", replaceHostInUrl("http://www.test.com:80/me/out?it=5","super:8080"));
assertEquals("http://super/me/out?it=5&test=5", replaceHostInUrl("http://www.test.com:80/me/out?it=5&test=5","super:80"));
assertEquals("https://super:80/me/out?it=5&test=5", replaceHostInUrl("https://www.test.com:80/me/out?it=5&test=5","super:80"));
assertEquals("https://super/me/out?it=5&test=5", replaceHostInUrl("https://www.test.com:80/me/out?it=5&test=5","super:443"));
assertEquals("http://super:443/me/out?it=5&test=5", replaceHostInUrl("http://www.test.com:443/me/out?it=5&test=5","super:443"));
assertEquals("http://super:443/me/out?it=5&test=5", replaceHostInUrl("HTTP://www.test.com:443/me/out?it=5&test=5","super:443"));
assertEquals("http://SUPERDUPER:443/ME/OUT?IT=5&TEST=5", replaceHostInUrl("HTTP://WWW.TEST.COM:443/ME/OUT?IT=5&TEST=5","SUPERDUPER:443"));
assertEquals("https://SUPERDUPER:23/ME/OUT?IT=5&TEST=5", replaceHostInUrl("HTTPS://WWW.TEST.COM:22/ME/OUT?IT=5&TEST=5","SUPERDUPER:23"));
assertEquals(null, replaceHostInUrl(null, null));
}
public static String replaceHostInUrl(String url, String newHost)
{
if (url == null || newHost == null)
{
return url;
}
try
{
URL originalURL = new URL(url);
boolean hostHasPort = newHost.indexOf(":") != -1;
int newPort = originalURL.getPort();
if (hostHasPort)
{
URL hostURL = new URL("http://" + newHost);
newHost = hostURL.getHost();
newPort = hostURL.getPort();
}
else
{
newPort = -1;
}
// Use implicit port if it's a default port
boolean isHttps = originalURL.getProtocol().equals("https");
boolean useDefaultPort = (newPort == 443 && isHttps) || (newPort == 80 && !isHttps);
newPort = useDefaultPort ? -1 : newPort;
URL newURL = new URL(originalURL.getProtocol(), newHost, newPort, originalURL.getFile());
String result = newURL.toString();
return result;
}
catch (MalformedURLException e)
{
throw new RuntimeException("Couldnt replace host in url, originalUrl=" + url + ", newHost=" + newHost);
}
}
public static void assertEquals(String expected, String actual)
{
if (expected == null && actual == null)
{
System.out.println("TEST PASSED, expected:" + expected + ", actual:" + actual);
return;
}
if (! expected.equals(actual))
throw new RuntimeException("Not equal! expected:" + expected + ", actual:" + actual);
System.out.println("TEST PASSED, expected:" + expected + ", actual:" + actual);
}
}
I realize this is a pretty old question; but posting a simpler solution in case someone else needs it.
String newUrl = new URIBuilder(URI.create(originalURL)).setHost(newHost).build().toString();
I've added a method to do this in the RawHTTP library, so you can simply do this:
URI uri = RawHttp.replaceHost(oldUri, "new-host");
Added in this commit: https://github.com/renatoathaydes/rawhttp/commit/cbe439f2511f7afcb89b5a0338ed9348517b9163#diff-ff0fec3bc023897ae857b07cc3522366
Feeback welcome, will release it soon.
Or using some regex magic:
public static String replaceHostInUrl(String url, String newHost) {
if (url == null || newHost == null) {
return null;
}
String s = url.replaceFirst("(?i)(?<=(https?)://)(www.)?\\w*(.com)?(:\\d*)?", newHost);
if (s.contains("http://")) {
s = s.replaceFirst(":80(?=/)", "");
} else if (s.contains("https://")) {
s = s.replaceFirst(":443(?=/)", "");
}
Matcher m = Pattern.compile("HTTPS?").matcher(s);
if (m.find()) {
s = s.replaceFirst(m.group(), m.group().toLowerCase());
}
return s;
}

Fast java routine to determine if request URI is within another URL

In a class (Java8), I have a String representing an HTTP URL, e.g. String str1="http://www.foo.com/bar", and another string containing a request URI e.g. str2="/bar/wonky/wonky.html".
What is the fastest way in terms of code execution to determine if str2 is within the context of str1 (e.g. the context is /bar) and then construct the complete url String result = "http://www.foo.com/bar/wonky/wonky.html"?
Well I don't know if there is a faster way to just use String.indexOf(). Here is an approach that I think covers the example you gave (demo):
public static boolean overlap(String a, String b_context) {
//Assume the a URL starts with http:// or https://, the next / is the start of the a_context
int root_index = a.indexOf("/", 8);
String a_context = a.substring(root_index);
String a_host = a.substring(0, root_index);
return b_context.startsWith(a_context);
}
Here is a function that uses the same logic but to combine the two urls if they overlap or throw an exception if they don't
public static String combine(String a, String b_context) {
//Assume the a URL starts with http:// or https://, the next / is the start of the a_context
int root_index = a.indexOf("/", 8);
String a_context = a.substring(root_index);
String a_host = a.substring(0, root_index);
if(b_context.startsWith(a_context)) {
return a_host + b_context;
} else {
throw new RuntimeException("urls do not overlap");
}
}
And here is an example of using them
public static void main(String ... args) {
System.out.println(combine("http://google.com/search", "/search?query=Java+String+Combine"));
System.out.println(combine("http://google.com/search", "/mail?inbox=Larry+Page"));
}

How can I retrieve HttpServletRequest data while using Jersey

I know that this is an easy one if I am not using Jersey and would use something like this:
Enumeration<String> params = request.getParameterNames();
while(params.hasMoreElements()){
String paramName = (String)params.nextElement();
System.out.println("Parameter Name - "+paramName+", Value - "+request.getParameter(paramName));
}
params = request.getHeaderNames();
while(params.hasMoreElements()){
String paramName = (String)params.nextElement();
System.out.println("Header Name - "+paramName+", Value - "+request.getHeader(paramName));
}
params = request.getAttributeNames();
while(params.hasMoreElements()){
String paramName = (String)params.nextElement();
System.out.println("Attribute Name - "+paramName+", Value - "+request.getAttribute(paramName));
}
I am also aware that I can do this and be done with it.
#FormParam("location") String location
But what if I do want to dump all the contents of the form submitted via POST?
The problem is that I am using Jersey as the implementation of JAX-RS and using the code above outputs this:
Attribute Name - org.glassfish.jersey.server.spring.scope.RequestContextFilter.REQUEST_ATTRIBUTES, Value - org.glassfish.jersey.server.spring.scope.JaxrsRequestAttributes#11e035a
Attribute Name - org.glassfish.jersey.message.internal.TracingLogger, Value - org.glassfish.jersey.message.internal.TracingLogger$1#16e45c8
I am guessing that my data is contained here: JaxrsRequestAttributes I am not sure though.
I know I am missing something here. This isn't supposed to be difficult isn't it?
UPDATE
As suggested Sotirios,
This is the code get the dump of the form.
try {
InputStream is = request.getInputStream();
int i;
char c;
while((i=is.read())!=-1)
{
// converts integer to character
c=(char)i;
// prints character
System.out.print(c);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
In order for this to work, I had to remove #FormParam in my parameter and leave out #Context HttpSerlvetRequest request.
Are there no other way to output this in a more elegant way with out the need to remove #FormParam? Maybe get the values from JaxrsRequestAttributes?
I tried to create a variable JaxrsRequestAttributes but it's a default class a can not access it directly.
Based on Sotirios comment's, here's the answer:
Here's the method signature
public Response authenticateUser(MultivaluedMap<String, String> form)
Iterator<String> it = form.keySet().iterator();
while(it.hasNext()){
String theKey = (String)it.next();
System.out.println("Parameter Name - "+theKey+", Value - "+form.getFirst(theKey));
}
System.out.println(form);
The HttpServletRequest can be accessed using :
#Context
private HttpServletRequest request;
Isn't that enough?

Store #PathParam values from REST call in a list or array

My function looks like this:
#PUT
#Path("property/{uuid}/{key}/{value}")
#Produces("application/xml")
public Map<String,ValueEntity> updateProperty(#Context HttpServletRequest request,
#PathParam("key") String key,
#PathParam("value") String value,
#PathParam("uuid") String uuid) throws Exception {
...
}
I have to modify it, so it accepts indefinite(or many) list of key-value pairs from REST call, something like
#Path("property/{uuid}/{key1}/{value1}/{key2}/{value2}/{key3}/{value3}/...")
Is it possible to store them in an array or list, so I do not list dozens of #PathParams and parameters, to avoid this:
#PathParam("key1") String key1,
#PathParam("key2") String key2,
#PathParam("key3") String key3,
Might be a good opportunity to rethink this design. By using /s, we are in a way signifying, with each / that we are trying to locate a different resource. Key/Value pairs (in the context of the URL) are mainly for query parameters or matrix parameters.
If /property/{uuid} is the path to a main resource, and we just want to offer some parameters to the client for accessing this resource, then we could allow matrix parameters or query parameters
Matrix Parameters (in a request url) will look something like
/12345;key1=value1;key2=value2;key3=value3
A resource method to obtain the values might look something like
#GET
#Path("/property/{uuid}")
public Response getMatrix(#PathParam("uuid") PathSegment pathSegment) {
StringBuilder builder = new StringBuilder();
// Get the {uuid} value
System.out.println("Path: " + pathSegment.getPath());
MultivaluedMap matrix = pathSegment.getMatrixParameters();
for (Object key : matrix.keySet()) {
builder.append(key).append(":")
.append(matrix.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
See PathSegment
Query Parameters (in a request url) might look something like
/12345?key1=value1&key2=value2&key3=value3
A resource method to obtain the values might look something like
#GET
#Path("/property/{uuid}")
public Response getQuery(#PathParam("uuid") String uuid,
#Context UriInfo uriInfo) {
MultivaluedMap params = uriInfo.getQueryParameters();
StringBuilder builder = new StringBuilder();
for (Object key : params.keySet()) {
builder.append(key).append(":")
.append(params.getFirst(key)).append("\n");
}
return Response.ok(builder.toString()).build();
}
See UriInfo
The difference is that Matrix parameters can be embedded into path segments, while query parameters must be placed at the end of the URL. You can also notice a little difference in syntax.
Some Resources
Query String (Wikipedia)
When to use query parameters versus matrix parameters?
URL matrix parameters vs. request parameters
UPDATE
Also looking at the PUT in you method signature, it appears you are trying update a resource using the path as the values for which you are trying to update, as I don't see any parameters in your method for an entity body. When PUTting, you should be sending the representation in the the entity body, not as as path segments or parameters.
A workaround:
#Path("/foo/bar/{other: .*}
public Response foo(#PathParam("other") VariableStrings vstrings) {
String[] splitPath = vstrings.getSplitPath();
}
VariableStrings class:
public class VariableStrings {
private String[] splitPath;
public VariableStrings(String unparsedPath) {
splitPath = unparsedPath.split("/");
}
}
Path segment sequence to vararg array in JAX-RS / Jersey?
Another example where you map the optional parameter to a Map:
#GET
# Produces({"application/xml", "application/json", "plain/text"})
# Path("/location/{locationId}{path:.*}")
public Response getLocation(#PathParam("locationId") int locationId, #PathParam("path") String path) {
Map < String, String > params = parsePath(path);
String format = params.get("format");
if ("xml".equals(format)) {
String xml = "<location<</location<<id<</id<" + locationId + "";
return Response.status(200).type("application/xml").entity(xml).build();
} else if ("json".equals(format)) {
String json = "{ 'location' : { 'id' : '" + locationId + "' } }";
return Response.status(200).type("application/json").entity(json).build();
} else {
String text = "Location: id=" + locationId;
return Response.status(200).type("text/plain").entity(text).build();
}
}
private Map < String, String > parsePath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
String[] pathParts = path.split("/");
Map < String, String > pathMap = new HashMap < String, String > ();
for (int i = 0; i < pathParts.length / 2; i++) {
String key = pathParts[2 * i];
String value = pathParts[2 * i + 1];
pathMap.put(key, value);
}
return pathMap;
}

Categories