problem in connecting to https url - java

I am able to connect to http url's but when
the server moved to https, my code is not working.
Can anyone help me in geeting it right with minimal changes.
I am using the following manager file (open source code)
for doing all kind of http request (uploading file,
downloading file or simple authentications).
I tried using the httpsUrlConnection as well but i guess,
i am missing something there. Please suggest something...
public class ClientHttpRequest
{
HttpURLConnection connection;
OutputStream os = null;
public static int responseCode;
public static String responseContentLength;
protected void connect() throws IOException
{
if (os == null) os = connection.getOutputStream();
}
protected void write(char c) throws IOException
{
connect();
os.write(c);
}
protected void write(String s) throws IOException
{
connect();
os.write(s.getBytes());
}
protected void newline() throws IOException
{
connect();
write("\r\n");
}
protected void writeln(String s) throws IOException
{
connect();
write(s);
newline();
}
private static Random random = new Random();
protected static String randomString() {
return Long.toString(random.nextLong(), 36);
}
String boundary = "---------------------------" + randomString() + randomString() + randomString();
private void boundary() throws IOException
{
write("--");
write(boundary);
}
/**
* Creates a new multipart POST HTTP request on a freshly opened URLConnection
* #param connection an already open URL connection
* #throws IOException
*/
public ClientHttpRequest(HttpURLConnection connection) throws IOException
{
this.connection = connection;
connection.setDoOutput(true);
connection.setConnectTimeout(20000);
connection.setReadTimeout(0);
connection.setUseCaches(false);
connection.setRequestProperty("Content-Type","multipart/form-data; boundary=" + boundary);
}
/**
* Creates a new multipart POST HTTP request for a specified URL
* #param url the URL to send request to
* #throws IOException
*/
public ClientHttpRequest(URL url) throws IOException
{
this((HttpURLConnection)url.openConnection());
}
/**
* Creates a new multipart POST HTTP request for a specified URL string
* #param urlString the string representation of the URL to send request to
* #throws IOException
*/
public ClientHttpRequest(String urlString) throws IOException
{
this(new URL(urlString));
}
private void writeName(String name) throws IOException
{
newline();
write("Content-Disposition: form-data; name=\"");
write(name);
write('"');
}
/**
* adds a string parameter to the request
* #param name parameter name
* #param value parameter value
* #throws IOException
*/
public void setParameter(String name, String value) throws IOException
{
boundary();
writeName(name);
newline(); newline();
writeln(value);
}
private static void pipe(InputStream in, OutputStream out) throws IOException
{
byte[] buf = new byte[500000];
int nread;
int total = 0;
synchronized (in)
{
while((nread = in.read(buf, 0, buf.length)) >= 0)
{
out.write(buf, 0, nread);
total += nread;
}
}
out.flush();
buf = null;
}
/**
* adds a file parameter to the request
* #param name parameter name
* #param filename the name of the file
* #param is input stream to read the contents of the file from
* #throws IOException
*/
public void setParameter(String name, String filename, InputStream is) throws IOException
{
boundary();
writeName(name);
write("; filename=\"");
write(filename);
write('"');
newline();
write("Content-Type: ");
String type = URLConnection.guessContentTypeFromName(filename);
if (type == null)
{
type = "application/octet-stream";
}
writeln(type);
newline();
pipe(is, os);
newline();
}
/**
* adds a file parameter to the request
* #param name parameter name
* #param file the file to upload
* #throws IOException
*/
public void setParameter(String name, File file) throws IOException
{
setParameter(name, file.getPath(), new FileInputStream(file));
}
/**
* adds a parameter to the request; if the parameter is a File, the file is uploaded, otherwise the string value of the parameter is passed in the request
* #param name parameter name
* #param object parameter value, a File or anything else that can be stringified
* #throws IOException
*/
public void setParameter(String name, Object object) throws IOException
{
if (object instanceof File)
{
setParameter(name, (File)object);
}
else
{
setParameter(name, object.toString());
}
}
/**
* adds parameters to the request
* #param parameters array of parameter names and values (parameters[2*i] is a name, parameters[2*i + 1] is a value); if a value is a file, the file is uploaded, otherwise it is stringified and sent in the request
* #throws IOException
*/
public void setParameters(Object[] parameters) throws IOException
{
if (parameters == null) return;
for (int i = 0; i < parameters.length - 1; i+=2)
{
setParameter(parameters[i].toString(), parameters[i+1]);
}
}
/**
* posts the requests to the server, with all the cookies and parameters that were added
* #return input stream with the server response
* #throws IOException
*/
public InputStream post() throws IOException
{
boundary();
writeln("--");
os.close();
InputStream inputStream = null;
try
{
responseCode = connection.getResponseCode();
responseContentLength = connection.getHeaderField("Content-Length");
inputStream = connection.getInputStream();
}
catch(Exception exception)
{
exception.printStackTrace();
responseCode = connection.getResponseCode();
inputStream = connection.getErrorStream();
}
return inputStream;
}
/**
* posts the requests to the server, with all the cookies and parameters that were added before (if any), and with parameters that are passed in the argument
* #param parameters request parameters
* #return input stream with the server response
* #throws IOException
* #see setParameters
*/
public InputStream post(Object[] parameters) throws IOException
{
setParameters(parameters);
return post();
}
/**
* post the POST request to the server, with the specified parameter
* #param name parameter name
* #param value parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public InputStream post(String name, Object value) throws IOException
{
setParameter(name, value);
return post();
}
/**
* post the POST request to the server, with the specified parameters
* #param name1 first parameter name
* #param value1 first parameter value
* #param name2 second parameter name
* #param value2 second parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public InputStream post(String name1, Object value1, String name2, Object value2) throws IOException
{
setParameter(name1, value1);
return post(name2, value2);
}
/**
* post the POST request to the server, with the specified parameters
* #param name1 first parameter name
* #param value1 first parameter value
* #param name2 second parameter name
* #param value2 second parameter value
* #param name3 third parameter name
* #param value3 third parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException
{
setParameter(name1, value1);
return post(name2, value2, name3, value3);
}
/**
* post the POST request to the server, with the specified parameters
* #param name1 first parameter name
* #param value1 first parameter value
* #param name2 second parameter name
* #param value2 second parameter value
* #param name3 third parameter name
* #param value3 third parameter value
* #param name4 fourth parameter name
* #param value4 fourth parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public InputStream post(String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException
{
setParameter(name1, value1);
return post(name2, value2, name3, value3, name4, value4);
}
/**
* posts a new request to specified URL, with parameters that are passed in the argument
* #param parameters request parameters
* #return input stream with the server response
* #throws IOException
* #see setParameters
*/
public static InputStream post(URL url, Object[] parameters) throws IOException
{
return new ClientHttpRequest(url).post(parameters);
}
/**
* post the POST request specified URL, with the specified parameter
* #param name parameter name
* #param value parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public static InputStream post(URL url, String name1, Object value1) throws IOException
{
return new ClientHttpRequest(url).post(name1, value1);
}
/**
* post the POST request to specified URL, with the specified parameters
* #param name1 first parameter name
* #param value1 first parameter value
* #param name2 second parameter name
* #param value2 second parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public static InputStream post(URL url, String name1, Object value1, String name2, Object value2) throws IOException
{
return new ClientHttpRequest(url).post(name1, value1, name2, value2);
}
/**
* post the POST request to specified URL, with the specified parameters
* #param name1 first parameter name
* #param value1 first parameter value
* #param name2 second parameter name
* #param value2 second parameter value
* #param name3 third parameter name
* #param value3 third parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3) throws IOException
{
return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3);
}
/**
* post the POST request to specified URL, with the specified parameters
* #param name1 first parameter name
* #param value1 first parameter value
* #param name2 second parameter name
* #param value2 second parameter value
* #param name3 third parameter name
* #param value3 third parameter value
* #param name4 fourth parameter name
* #param value4 fourth parameter value
* #return input stream with the server response
* #throws IOException
* #see setParameter
*/
public static InputStream post(URL url, String name1, Object value1, String name2, Object value2, String name3, Object value3, String name4, Object value4) throws IOException
{
return new ClientHttpRequest(url).post(name1, value1, name2, value2, name3, value3, name4, value4);
}
}

sample code for Disabling Certificate Validation in an HTTPS Connection
http://exampledepot.com/egs/javax.net.ssl/TrustAll.html

use this code in yr java prog
try {
logger.info("Importing the Https certificate..");
/* ----------- Importing the Https certificate -----------*/
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
#Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
#Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
System.out.println("Exception" + e);
}
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String string, SSLSession ssls) {
return true;
}
});
and see this link u have to make change in server.xml

Related

scan IP without SNMP agent

Using as an example a following code from https://www.jitendrazaa.com/blog/java/snmp/create-snmp-client-in-java-using-snmp4j/ to monitor a network when I send OIDs to an empty IP or to a device without SNMP the program throws an exception.
I use a for loop to read IPs. I have tried to change the flow of execution in different ways without success.
the program falls in the getAsStrint method with java.lang.NullPointerException
public class SNMPManager {
Snmp snmp = null;
String address = null;
/**
* Constructor
*
* #param add
*/
public SNMPManager(String add) {
address = add;
}
public static void main(String[] args) throws IOException {
/**
* Port 161 is used for Read and Other operations
* Port 162 is used for the trap generation
*/
for (int i = 37; i < 40; i++) {
System.out.println("ip x.x.x." + i);
SNMPManager client = new SNMPManager("udp:192.168.1." + i + "/161");
//SNMPManager client = new SNMPManager("udp:192.168.1.37/161");
client.start();
/**
* OID - .1.3.6.1.2.1.1.1.0 => SysDec
* OID - .1.3.6.1.2.1.1.5.0 => SysName
* => MIB explorer will be usefull here, as discussed in previous article
*/
String sysDescr = client.getAsString(new OID(".1.3.6.1.2.1.1.5.0"));
System.out.println(".1.3.6.1.2.1.1.5.0" + " - SysName: " + sysDescr);
String sysDescr2 = client.getAsString(new OID(".1.3.6.1.2.1.1.1.0"));
System.out.println(".1.3.6.1.2.1.1.1.0" + " - SysDec: " + sysDescr2);
}
}
/**
* Start the Snmp session. If you forget the listen() method you will not
* get any answers because the communication is asynchronous
* and the listen() method listens for answers.
*
* #throws IOException
*/
private void start() throws IOException {
TransportMapping transport = new DefaultUdpTransportMapping();
snmp = new Snmp(transport);
// Do not forget this line!
transport.listen();
}
/**
* Method which takes a single OID and returns the response from the agent as a String.
*
* #param oid
* #return
* #throws IOException
*/
public String getAsString(OID oid) throws IOException {
ResponseEvent event = get(new OID[]{oid});
return event.getResponse().get(0).getVariable().toString();
}
/**
* This method is capable of handling multiple OIDs
*
* #param oids
* #return
* #throws IOException
*/
public ResponseEvent get(OID oids[]) throws IOException {
PDU pdu = new PDU();
for (OID oid : oids) {
pdu.add(new VariableBinding(oid));
}
pdu.setType(PDU.GET);
ResponseEvent event = snmp.send(pdu, getTarget(), null);
if (event != null) {
return event;
}
throw new RuntimeException("GET timed out");
}
/**
* This method returns a Target, which contains information about
* where the data should be fetched and how.
*
* #return
*/
private Target getTarget() {
Address targetAddress = GenericAddress.parse(address);
CommunityTarget target = new CommunityTarget();
target.setCommunity(new OctetString("public"));
target.setAddress(targetAddress);
target.setRetries(2);
target.setTimeout(1500);
target.setVersion(SnmpConstants.version2c);
return target;
}
make getAsString(OID oid) method like this
public String getAsString(OID oid) throws IOException {
ResponseEvent event = get(new OID[]{oid});
if(event.getResponse() != null){
return event.getResponse().get(0).getVariable().toString();
} else {
return "no target"
}
}
there are no target that is why null pointer exception

inputstream null pointer exception when using modified last.fm's Caller.java

For some reason I'm getting null pointer exception. It's downloading the image here and logcat points me to call
public Result call(final String method, final String apiKey, final String... params) {
return call(method, apiKey, map(params));
}
/**
* Performs the web-service call. If the <code>session</code> parameter is
* <code>non-null</code> then an authenticated call is made. If it's
* <code>null</code> then an unauthenticated call is made.<br/>
* The <code>apiKey</code> parameter is always required, even when a valid
* session is passed to this method.
*
* #param method The method to call
* #param apiKey A Last.fm API key
* #param params Parameters
* #param session A Session instance or <code>null</code>
* #return the result of the operation
*/
public Result call(final String method, final String apiKey, Map<String, String> params) {
params = new WeakHashMap<String, String>(params);
InputStream inputStream = null;
// no entry in cache, load from web
if (inputStream == null) {
// fill parameter map with apiKey and session info
params.put(PARAM_API_KEY, apiKey);
try {
final HttpURLConnection urlConnection = openPostConnection(method, params);
inputStream = getInputStreamFromConnection(urlConnection);
if (inputStream == null) {
lastResult = Result.createHttpErrorResult(urlConnection.getResponseCode(),
urlConnection.getResponseMessage());
return lastResult;
}
} catch (final IOException ignored) {
}
}
try {
final Result result = createResultFromInputStream(inputStream);
lastResult = result;
return result;
} catch (final IOException ignored) {
} catch (final SAXException ignored) {
}
return null;
}
It finally cracks at the line "new InputSource(new InputStreamReader(inputStream, "UTF-8")));".
/**
* #param inputStream
* #return
* #throws SAXException
* #throws IOException
*/
private Result createResultFromInputStream(final InputStream inputStream) throws SAXException,
IOException {
final Document document = newDocumentBuilder().parse(
new InputSource(new InputStreamReader(inputStream, "UTF-8")));
final Element root = document.getDocumentElement(); // lfm element
final String statusString = root.getAttribute("status");
final Status status = "ok".equals(statusString) ? Status.OK : Status.FAILED;
if (status == Status.FAILED) {
final Element errorElement = (Element)root.getElementsByTagName("error").item(0);
final int errorCode = Integer.parseInt(errorElement.getAttribute("code"));
final String message = errorElement.getTextContent();
return Result.createRestErrorResult(errorCode, message);
} else {
return Result.createOkResult(document);
}
}
Any ideas? I have no idea what might be wrong. If sufficient info is provided then let me know - I'll get what you need. I'm a beginner. :)

Extracting data from Json object by http GET

I am working on android app and I want to know how to get data from Json object by using http GET the (the http request url is APIary)
It's my first time to use Json and httpRequests so I don't know the syntax needed for this
That's my HttpRequest class I'm using :
public abstract class HttpRequest extends AsyncTask<String, String, String> {
private HttpClient httpClient;
private HttpRequestBase request;
private boolean hasError = false;
private String errorMessage = null;
private boolean hasBody = false;
private int statusCode;
public HttpRequest(){
httpClient = new DefaultHttpClient();
}
/**
* This method is called from the subclasses to pass the request method used to this class
* #param request , The request class passed from the subclass
*/
void setMethod(HttpRequestBase request){
this.request = request;
}
/**
* Adds a header to the current request
* #param header , header key
* #param value , header value
*/
public void addHeader(String header,String value){
this.request.addHeader(header, value);
}
/**
* #return false if the status code was anything other than 2XX after executing the request , true otherwise
*/
public boolean hasError() {
return hasError;
}
/**
* A getter for the error message
* #return String the error message returned from the request if any
*/
public String getErrorMessage() {
return errorMessage;
}
/**
* This is the method responsible for executing the request and handling the response
* #return String , The response body , null in case of errors
*/
#Override
protected String doInBackground(String... args) {
if(hasBody){
this.request.addHeader("content-type", "application/json");
}
ResponseHandler<String> handler = new BasicResponseHandler();
HttpResponse x = null;
try{
x = httpClient.execute(this.request);
this.statusCode = x.getStatusLine().getStatusCode();
return handler.handleResponse(x);
}catch(ClientProtocolException e ){
hasError = true;
errorMessage = e.getMessage();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* A getter method for the status code
* #return int , the status code of executing the request
*/
public int getStatusCode(){
return this.statusCode;
}
/**
* A setter method to set whether the request has a body or not , used between this class and its subclasses
* #param hasBody boolean
*/
void setHasBody(boolean hasBody){
this.hasBody = hasBody;
}
}
I think this post can help you :
How to parse JSON in Android
Tell me if don't understand !

Error with Java HTTP Server: Unexpected end of file from server

java.net.SocketException: Unexpected end of file from server
The client sends a query to the server by using an URL. I have a HTTPServer that parses info from the URL. Using that info, the server does some work and then returns the response to the client.
Let's say the URL is:
http://localhost:9090/find?term=healthy&term=cooking&count=3
This works fine. But when count is greater or equal to 4, I get java.net.SocketException.
To debug the error, I print out the URL. System.out.println(input);
When count>=4, the URL gets printed two times in the console. Please help.
private final HttpServer server;
public Server(int port){
server = HttpServer.create(new InetSocketAddress(port), MAX_BACKLOG);
server.createContext("/isbn", new ISBNHandler());
server.createContext("/find", new TitleHandler());
}
static class TitleHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
int count=5;
String input=t.getRequestURI().toASCIIString();//get the URL
System.out.println(input);
//using info from URL to do some work
String response = builder.toString();//StringBuilder
// System.out.println(response);
t.sendResponseHeaders(200, response.getBytes().length);
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
Exception
java.net.SocketException: Unexpected end of file from server at
sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source) at
sun.net.www.http.HttpClient.parseHTTP(Unknown Source) at
sun.net.www.http.HttpClient.parseHTTPHeader(Unknown Source) at
sun.net.www.http.HttpClient.parseHTTP(Unknown Source) at
sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown
Source) at java.net.HttpURLConnection.getResponseCode(Unknown Source)
at TestHarness.assertJSONResponse(TestHarness.java:101) at
TestHarness.testServer(TestHarness.java:38) at
TestHarness.main(TestHarness.java:25)
TestHarness
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Sample main method with initial acceptance tests to help you along
*/
public class TestHarness {
private static Pattern MAP_PATTERN = Pattern.compile("(['\"])(.*?)\\1:\\s*(['\"])(.*?)\\3");
private static Pattern LIST_PATTERN = Pattern.compile("\\{(.*?)\\}");
public static void main(String[] args) throws IOException {
/*
if (args.length < 1) {
System.out.println("The test harness requires a single parameter: the location of the CSV file to parse");
}
*/
BookServer server = new BookServer(9090, new File("books.csv"));
server.start();
testServer();
server.stop();
}
/**
* Run initial acceptance tests
*/
#SuppressWarnings("unchecked")
private static void testServer() {
assertJSONResponse("Book Test", "http://localhost:9090/isbn/9780470052327",
createMap("isbn", "9780470052327", "title", "Techniques of Healthy Cooking", "author", "Mary Dierdre Donovan", "publisher", "Wiley", "publishedYear", "2007"));
assertJSONResponse("Book Test", "http://localhost:9090/isbn/9780451169525",
createMap("isbn", "9780451169525", "title", "Misery", "author", "Stephen King", "publisher", "Signet", "publishedYear", "1987"));
assertJSONResponse("Query Test", "http://localhost:9090/find?term=healthy&term=cooking&count=4",
Arrays.asList(createMap("isbn", "9780470052327", "title", "Techniques of Healthy Cooking", "author", "Mary Dierdre Donovan", "publisher", "Wiley", "publishedYear", "2007")));
}
/**
* Helper method to convert the vararg parameters into a Map. Assumes alternating key, value, key, value... and calls
* toString on all args
*
* #param args the parameters to put in the map, alternating key ancd value
* #return Map of String representations of the parameters
*/
private static Map<String, String> createMap(Object ... args) {
Map<String, String> map = new HashMap<String, String>();
for (int i=0; i < args.length; i+=2) {
map.put(args[i].toString(), args[i+1].toString());
}
return map;
}
/**
* Parses a JSON list of maps
* NOTE: assumes all keys and values in the nested maps are quoted
*
* #param content the JSON representation
* #return a list of parsed Map content
*/
private static List<Map<String, String>> parseJSONList(CharSequence content) {
List<Map<String, String>> list = new ArrayList<Map<String, String>>();
Matcher m = LIST_PATTERN.matcher(content);
while(m.find()) {
list.add(parseJSONMap(m.group(1)));
}
return list;
}
/**
* Parse JSON encoded content into a Java Map.
* NOTE: Assumes that all elements in the map are quoted
*
* #param content the JSON representation to be parsed
* #return A map of parsed content
*/
private static Map<String, String> parseJSONMap(CharSequence content) {
Map<String, String> map = new HashMap<String, String>();
Matcher m = MAP_PATTERN.matcher(content);
while (m.find()) {
map.put(m.group(2), m.group(4));
}
return map;
}
/**
* Retrieve content from a test URL and assert that its content is the expected. Results will be printed to System.out for convenience
*
* #param testName Name of the test, to be used simply for labelling
* #param urlString The URL to test
* #param expected The content expected at that URL
*/
private static void assertJSONResponse(String testName, String urlString, Object expected) {
try {
URL url = new URL(urlString);
HttpURLConnection con = ((HttpURLConnection)url.openConnection());
if (!assertTest(testName + " - response code", con.getResponseCode(), 200)) return;
StringBuilder b = new StringBuilder();
BufferedReader r = new BufferedReader(new InputStreamReader(con.getInputStream()));
String line;
while((line = r.readLine()) != null) b.append(line);
String result = b.toString();
assertTest(testName + " - content retrieved", !result.isEmpty(), true);
Object parsed = result.trim().startsWith("[") ? parseJSONList(result) : parseJSONMap(result);
assertTest(testName + " - parsed content match", parsed, expected);
} catch (Exception e) {
System.out.println(testName + ": <<<FAILED with Exception>>>");
e.printStackTrace(System.out);
}
}
/**
* Log the results of a test assertion
*
* #param testName Name of the test, to be used simply for labelling
* #param result The result of the operation under test
* #param expected The expected content that the result will be compared against
* #return whether the test was successful
*/
private static boolean assertTest(String testName, Object result, Object expected) {
boolean passed = result.equals(expected);
System.out.println(testName + (passed ? ": <<<PASSED>>>" : String.format(": <<<FAILED>>> expected '%s' but was '%s'", expected, result)));
return passed;
}
}
I fixed the error. The server calls a private sorting function, but I made a bug in the sorting function. The server crashed.

Modify HttpServletRequest body

I'm working on legacy code and need to make a patch.
The problem: an ancient application sends bad HTTP POST requests. One of the parameters is not URL encoded. I know that this parameter always comes last and I know it's name. I'm now trying to fix it on the server side which is running inside tomcat.
This parameter is not accessible via standard getParameter method of HttpServletRequest, since it's malformed. Method simply returns null. But when I manually read the whole body of request through ServletInputStream all the other parameters disappear. Looks like underlying classes can't parse contents of ServletInputStream since it's drained out.
So far I've managed to make a wrapper that reads all parameters from body and overrides all parameter access methods. But if any filter in the chain before mine will try to access any parameter, everything will break since ServletInputStream will be empty.
Can I somehow evade this problem? May be there's different approach?
To summarize, If I'll read raw request body in the filter, parameters will disappear from the request. If I read single parameter, ServletInputStream will become empty and manual processing will be impossible. Moreover, it's impossible to read malformed parameter via getParameter method.
Solution I've found:
It's not enough to just redefine parameter accessing methods. Several things must be done.
A filter is needed where request will be wrapped.
A custom HttpRequestWrapper is needed with all parameter access methods overridden. Request body should be parsed in constructor and stored as a field.
getInputStream and getReader methods should be redefined as well. They return values depend on the stored request body.
Custom class extending ServletInputStream is required since this one is abstract.
This 4 combined will allow you to use getParameter without interference with getInputStream and getReader methods.
Mind that manual request parameter parsing may get complicated with multipart requests. But that's another topic.
To clarify, I redefined parameter accessing methods because my request was damaged as stated in the question. You may not need that.
Rather than overriding methods, why don't you install a servlet filter which rewrites the request?
Jason Hunter has a pretty good article on filters.
I did a more complete wrapper that allows you to still access the content in the case Content-Type is application/x-www-form-urlencoded and you already called one of the getParameterXXX methods:
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.Principal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* This class implements the Wrapper or Decorator pattern.<br/>
* Methods default to calling through to the wrapped request object,
* except the ones that read the request's content (parameters, stream or reader).
* <p>
* This class provides a buffered content reading that allows the methods
* {#link #getReader()}, {#link #getInputStream()} and any of the getParameterXXX to be called
* safely and repeatedly with the same results.
* <p>
* This class is intended to wrap relatively small HttpServletRequest instances.
*
* #author pgurov
*/
public class HttpServletRequestWrapper implements HttpServletRequest {
private class ServletInputStreamWrapper extends ServletInputStream {
private byte[] data;
private int idx = 0;
ServletInputStreamWrapper(byte[] data) {
if(data == null)
data = new byte[0];
this.data = data;
}
#Override
public int read() throws IOException {
if(idx == data.length)
return -1;
return data[idx++];
}
}
private HttpServletRequest req;
private byte[] contentData;
private HashMap<String, String[]> parameters;
public HttpServletRequestWrapper() {
//a trick for Groovy
throw new IllegalArgumentException("Please use HttpServletRequestWrapper(HttpServletRequest request) constructor!");
}
private HttpServletRequestWrapper(HttpServletRequest request, byte[] contentData, HashMap<String, String[]> parameters) {
req = request;
this.contentData = contentData;
this.parameters = parameters;
}
public HttpServletRequestWrapper(HttpServletRequest request) {
if(request == null)
throw new IllegalArgumentException("The HttpServletRequest is null!");
req = request;
}
/**
* Returns the wrapped HttpServletRequest.
* Using the getParameterXXX(), getInputStream() or getReader() methods may interfere
* with this class operation.
*
* #return
* The wrapped HttpServletRequest.
*/
public HttpServletRequest getRequest() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return new HttpServletRequestWrapper(req, contentData, parameters);
}
/**
* This method is safe to use multiple times.
* Changing the returned array will not interfere with this class operation.
*
* #return
* The cloned content data.
*/
public byte[] getContentData() {
return contentData.clone();
}
/**
* This method is safe to use multiple times.
* Changing the returned map or the array of any of the map's values will not
* interfere with this class operation.
*
* #return
* The clonned parameters map.
*/
public HashMap<String, String[]> getParameters() {
HashMap<String, String[]> map = new HashMap<String, String[]>(parameters.size() * 2);
for(String key : parameters.keySet()) {
map.put(key, parameters.get(key).clone());
}
return map;
}
private void parseRequest() throws IOException {
if(contentData != null)
return; //already parsed
byte[] data = new byte[req.getContentLength()];
int len = 0, totalLen = 0;
InputStream is = req.getInputStream();
while(totalLen < data.length) {
totalLen += (len = is.read(data, totalLen, data.length - totalLen));
if(len < 1)
throw new IOException("Cannot read more than " + totalLen + (totalLen == 1 ? " byte!" : " bytes!"));
}
contentData = data;
String enc = req.getCharacterEncoding();
if(enc == null)
enc = "UTF-8";
String s = new String(data, enc), name, value;
StringTokenizer st = new StringTokenizer(s, "&");
int i;
HashMap<String, LinkedList<String>> mapA = new HashMap<String, LinkedList<String>>(data.length * 2);
LinkedList<String> list;
boolean decode = req.getContentType() != null && req.getContentType().equals("application/x-www-form-urlencoded");
while(st.hasMoreTokens()) {
s = st.nextToken();
i = s.indexOf("=");
if(i > 0 && s.length() > i + 1) {
name = s.substring(0, i);
value = s.substring(i+1);
if(decode) {
try {
name = URLDecoder.decode(name, "UTF-8");
} catch(Exception e) {}
try {
value = URLDecoder.decode(value, "UTF-8");
} catch(Exception e) {}
}
list = mapA.get(name);
if(list == null) {
list = new LinkedList<String>();
mapA.put(name, list);
}
list.add(value);
}
}
HashMap<String, String[]> map = new HashMap<String, String[]>(mapA.size() * 2);
for(String key : mapA.keySet()) {
list = mapA.get(key);
map.put(key, list.toArray(new String[list.size()]));
}
parameters = map;
}
/**
* This method is safe to call multiple times.
* Calling it will not interfere with getParameterXXX() or getReader().
* Every time a new ServletInputStream is returned that reads data from the begining.
*
* #return
* A new ServletInputStream.
*/
public ServletInputStream getInputStream() throws IOException {
parseRequest();
return new ServletInputStreamWrapper(contentData);
}
/**
* This method is safe to call multiple times.
* Calling it will not interfere with getParameterXXX() or getInputStream().
* Every time a new BufferedReader is returned that reads data from the begining.
*
* #return
* A new BufferedReader with the wrapped request's character encoding (or UTF-8 if null).
*/
public BufferedReader getReader() throws IOException {
parseRequest();
String enc = req.getCharacterEncoding();
if(enc == null)
enc = "UTF-8";
return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(contentData), enc));
}
/**
* This method is safe to execute multiple times.
*
* #see javax.servlet.ServletRequest#getParameter(java.lang.String)
*/
public String getParameter(String name) {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
String[] values = parameters.get(name);
if(values == null || values.length == 0)
return null;
return values[0];
}
/**
* This method is safe.
*
* #see {#link #getParameters()}
* #see javax.servlet.ServletRequest#getParameterMap()
*/
#SuppressWarnings("unchecked")
public Map getParameterMap() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return getParameters();
}
/**
* This method is safe to execute multiple times.
*
* #see javax.servlet.ServletRequest#getParameterNames()
*/
#SuppressWarnings("unchecked")
public Enumeration getParameterNames() {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
return new Enumeration<String>() {
private String[] arr = getParameters().keySet().toArray(new String[0]);
private int idx = 0;
public boolean hasMoreElements() {
return idx < arr.length;
}
public String nextElement() {
return arr[idx++];
}
};
}
/**
* This method is safe to execute multiple times.
* Changing the returned array will not interfere with this class operation.
*
* #see javax.servlet.ServletRequest#getParameterValues(java.lang.String)
*/
public String[] getParameterValues(String name) {
try {
parseRequest();
} catch (IOException e) {
throw new IllegalStateException("Cannot parse the request!", e);
}
String[] arr = parameters.get(name);
if(arr == null)
return null;
return arr.clone();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getAuthType()
*/
public String getAuthType() {
return req.getAuthType();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getContextPath()
*/
public String getContextPath() {
return req.getContextPath();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getCookies()
*/
public Cookie[] getCookies() {
return req.getCookies();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getDateHeader(java.lang.String)
*/
public long getDateHeader(String name) {
return req.getDateHeader(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getHeader(java.lang.String)
*/
public String getHeader(String name) {
return req.getHeader(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getHeaderNames()
*/
#SuppressWarnings("unchecked")
public Enumeration getHeaderNames() {
return req.getHeaderNames();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getHeaders(java.lang.String)
*/
#SuppressWarnings("unchecked")
public Enumeration getHeaders(String name) {
return req.getHeaders(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getIntHeader(java.lang.String)
*/
public int getIntHeader(String name) {
return req.getIntHeader(name);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getMethod()
*/
public String getMethod() {
return req.getMethod();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getPathInfo()
*/
public String getPathInfo() {
return req.getPathInfo();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getPathTranslated()
*/
public String getPathTranslated() {
return req.getPathTranslated();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getQueryString()
*/
public String getQueryString() {
return req.getQueryString();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRemoteUser()
*/
public String getRemoteUser() {
return req.getRemoteUser();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRequestURI()
*/
public String getRequestURI() {
return req.getRequestURI();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRequestURL()
*/
public StringBuffer getRequestURL() {
return req.getRequestURL();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getRequestedSessionId()
*/
public String getRequestedSessionId() {
return req.getRequestedSessionId();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getServletPath()
*/
public String getServletPath() {
return req.getServletPath();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getSession()
*/
public HttpSession getSession() {
return req.getSession();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getSession(boolean)
*/
public HttpSession getSession(boolean create) {
return req.getSession(create);
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#getUserPrincipal()
*/
public Principal getUserPrincipal() {
return req.getUserPrincipal();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromCookie()
*/
public boolean isRequestedSessionIdFromCookie() {
return req.isRequestedSessionIdFromCookie();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromURL()
*/
public boolean isRequestedSessionIdFromURL() {
return req.isRequestedSessionIdFromURL();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdFromUrl()
*/
#SuppressWarnings("deprecation")
public boolean isRequestedSessionIdFromUrl() {
return req.isRequestedSessionIdFromUrl();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isRequestedSessionIdValid()
*/
public boolean isRequestedSessionIdValid() {
return req.isRequestedSessionIdValid();
}
/* (non-Javadoc)
* #see javax.servlet.http.HttpServletRequest#isUserInRole(java.lang.String)
*/
public boolean isUserInRole(String role) {
return req.isUserInRole(role);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getAttribute(java.lang.String)
*/
public Object getAttribute(String name) {
return req.getAttribute(name);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getAttributeNames()
*/
#SuppressWarnings("unchecked")
public Enumeration getAttributeNames() {
return req.getAttributeNames();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getCharacterEncoding()
*/
public String getCharacterEncoding() {
return req.getCharacterEncoding();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getContentLength()
*/
public int getContentLength() {
return req.getContentLength();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getContentType()
*/
public String getContentType() {
return req.getContentType();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocalAddr()
*/
public String getLocalAddr() {
return req.getLocalAddr();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocalName()
*/
public String getLocalName() {
return req.getLocalName();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocalPort()
*/
public int getLocalPort() {
return req.getLocalPort();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocale()
*/
public Locale getLocale() {
return req.getLocale();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getLocales()
*/
#SuppressWarnings("unchecked")
public Enumeration getLocales() {
return req.getLocales();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getProtocol()
*/
public String getProtocol() {
return req.getProtocol();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRealPath(java.lang.String)
*/
#SuppressWarnings("deprecation")
public String getRealPath(String path) {
return req.getRealPath(path);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRemoteAddr()
*/
public String getRemoteAddr() {
return req.getRemoteAddr();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRemoteHost()
*/
public String getRemoteHost() {
return req.getRemoteHost();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRemotePort()
*/
public int getRemotePort() {
return req.getRemotePort();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getRequestDispatcher(java.lang.String)
*/
public RequestDispatcher getRequestDispatcher(String path) {
return req.getRequestDispatcher(path);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getScheme()
*/
public String getScheme() {
return req.getScheme();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getServerName()
*/
public String getServerName() {
return req.getServerName();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#getServerPort()
*/
public int getServerPort() {
return req.getServerPort();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#isSecure()
*/
public boolean isSecure() {
return req.isSecure();
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#removeAttribute(java.lang.String)
*/
public void removeAttribute(String name) {
req.removeAttribute(name);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String name, Object value) {
req.setAttribute(name, value);
}
/* (non-Javadoc)
* #see javax.servlet.ServletRequest#setCharacterEncoding(java.lang.String)
*/
public void setCharacterEncoding(String env)
throws UnsupportedEncodingException {
req.setCharacterEncoding(env);
}
}
I wanted to post this as a comment, but I do not have enough rep. Your solution is insufficient in that ServletInputStreamWrapper will return negative integers. For instance, mock a request with input encoding UTF-16, either big or little endian. The input may start with the Byte Order Mark indicating endianess, and when testing my statement please construct the mock request content to do so. http://en.wikipedia.org/wiki/Byte_order_mark#UTF-16 Either of these BOMs contains a 0xFF byte. Since java has no unsigned byte, this 0xFF is returned as a -1. To work around this, just change the read function like so
public int read() throws IOException {
if (index == data.length) {
return -1;
}
return data[index++] & 0xff;
}
I somewhat like your solution because it works well with Spring. At first I tried to eliminate some of the delegation code you wrote by extending from HttpServletRequestWrapper. However, Spring does something interesting: when it encounters a request of type ServletRequestWrapper it unwraps it, calling getRequest(). Problem being that my getRequest() method, as copied from your code, returns a new class that extends from HttpServletRequestWrapper... rinse and repeat infinitely. So it's sad to say, chalk up a win for not using interfaces!
You could write your own Servlet Filter and hopefully ensure that it appears first in the chain. Then wrap the ServletRequest object in something that will handle the re-writing where needed. Have a look at the Programming Customized Requests and Responses section of http://java.sun.com/products/servlet/Filters.html
------ Update ------
I must be missing something. You say you can read the request body and read the parameters yourself. Couldn't you then ensure your filter is first, wrap the ServletRequest object, read, process and store the parameters, pass your request object up the chain and offer the parameters you stored instead of the original ones?

Categories

Resources