Class method with HttpURLConnection can't scrape cookie JSP script
I have a simple Java class, MessageBinHashBundler, that will need to retrieve a nickname stored as a cookie value and place it into a display. This class does not include "javax.servlet.http.Cookie" because I have no ability to compile it otherwise as my PC can only take the most simplistic JVM installation on earth. Thus, instead of using the Cookie object, I have to use a class I wrote called CookieRetriever that does a URL scrape to obtain a cookie - it does this by scraping a URL that contains simple HTML tags and the cookie value, nothing more.
Here is the JSP script, "cookie_grabber.jsp":
<%@ page import="ppowell.*, javax.servlet.http.Cookie" %>
<%
// COMMENT TITLE GOES HERE
String cookie ="", cookieName ="";
cookieName = request.getParameter("name") !=null ? request.getParameter("name") : ChatGlobals.CHAT_COOKIE_NAME;
Cookie[] cookieArray = request.getCookies();
for (int i = 0; i < cookieArray.length; i++){
if (cookieArray[i].getName().trim().toLowerCase().equals(cookieName.trim().toLowerCase()) &&
cookieArray[i].getValue() !=null
){
cookie = cookieArray[i].getValue();
break;
}
}
%>
<html>
<head>
</head>
<body>
<%= cookie %>
</body>
</html>
I verified that this work as I see my cookie value plainly each time I pull up the URL in my browsers (IE 5.1, Netscape 7.0 and Firefox 1.0).
Here is the code to CookieRetriever.getCookieVal():
/**
* To use this method you will have to be sure to have your URL pass the name
* of the cookie and not necessarily the cookie object itself
*
* @access public
* @return String name of cookie
*/
public String getCookieVal(){// STRING METHOD
String stuff = null, cookieText ="";
try{
URL url =new URL(this.url +"?name=" + this.cookieName);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(false);
conn.setUseCaches(false);
conn.setDefaultUseCaches(false);
conn.setRequestProperty("Content-type","text/html");
conn.setRequestProperty("Connection","close");
conn.connect();
BufferedReader in =new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((stuff = in.readLine()) !=null) cookieText += stuff;
in.close();
conn.disconnect();
}catch (Exception e){
System.out.println("Could not connect to " + this.url +"?name=" + this.cookieName);
e.printStackTrace();
}finally{
cookieText = cookieText.replaceAll("[\\n\\r]+","").replaceAll("<[^>]+>","");
}
return cookieText.trim();
}
This time I bypassed within cookie_grabber.jsp the "query string problem" that plagued me before, and with or without query string, if I pull up "cookie_grabber.jsp" in my local browsers (all three of them), I see my cookie value. However, if I use CookieRetriever.getCookieVal(), every time I see NOTHING.
Could someone look at the code and tell me what's going wrong, I don't get it from here.
Thanx
Phil
if you take out the finally line: cookieText = cookieText.replaceAll("[\\n\\r]+", "").replaceAll("<[^>]+>", "");What does cookieText contain then?
cookieText contains the cookie value, e.g. if you cookie is "chat" your value will be the value of the cookie "chat", which is, in this case, your nickname you entered to get into the chatroom.Phil
Oops sorry I misread what you asked.If you take out the "finally" block, cookieText = ""Phil
Is there a way to edit your replies?
One last time..
cookieText is initialized as ""
If the data scrape was successful then it contains the cookie value.
If the data scrape was not successful then it contains ""
If you take out the finally block and the scrape was successful it contains an entire HTML page with the cookie value embedded in the HTML body
If you take out the finally block and the scrape was NOT successful it contains ""
Phil
Well then the problem has to be in that finally line, because up to that line everything is working as it should. I was kinda hoping you would figure that out by yourself.
Sorry, but that wasn't it. Took out the finally{} block and it returned "".
I have been trying a different approach now altogether, also to no avail:
Idea about passing an Enumeration object from MessageProcessor class to the MessageBinHashBundler class to the CookieRetriever class so that its getCookieVal() method would return, in the end, the cookie name.
Where did I go wrong?
Here is the code snippet to MessageProcessor.process() method:
// NEW 1/24/2006: LOOK FOR Enumeration OBJECT FIRST FOR MORE EFFICIENT MEANS OF HANDLING COOKIE via MessageBinHashBundler
Enumeration e = this.request.getHeaders("Cookie");// WILL RETURN AN Enumeration BASED UPON COOKIE INFO
if (e != null) {
bundler = new MessageBinHashBundler(this.nickname, (Object)e); // CREATE CLASS INSTANCE TO BUNDLE MESSAGE
} else {
bundler = new MessageBinHashBundler(this.nickname);
}
At this point "e" is a valid Enumeration and all is well. I figured that it be best to pass it as a serializable Object to recreate it later as another Enumeration, so that's why I did that.
So now we're in MessageBinHashBundler:
/**
* Constructor
*
* New 1/24/2006: Will override constructor by passing Object parameter (that was Enumeration)
*
* @access public
* @param String nickname
* @param Object enumm
*/
public MessageBinHashBundler(String nickname, Object enumm) {
this.nickname = nickname;
this.enumm = enumm;
if (this.enumm != null) this.willUseEnumeration = true;
}
/**
* Convert String message to Hashtable
*
* @access public
* @param String message
* @return Hashtable messageHash
* @uses CookieRetriever
* @uses ChatGlobals
*/
public Hashtable convert(String message) {
Hashtable messageHash = new Hashtable(1);
// NEW 1/21/2006: PREVENT THROWING NullPointerException BY RESETTING PARAMETER message TO "" IN CASE IT IS Null
if (message == null) message = "";
if (!this.isFromChatOp && this.nickname != null && !this.nickname.equals("")) {
messageHash.put(this.nickname, message);
} else if (!this.isFromChatOp && this.willUseEnumeration && this.enumm != null) {
// NEW 1/24/2006: USE Enumeration OBJECT WITH EMBEDDED COOKIE INFORMATION IF REQUESTED TO DO SO
CookieRetriever cr = new CookieRetriever(ChatGlobals.CHAT_COOKIE_NAME, this.enumm);
messageHash.put(cr.getCookieVal(this.willUseEnumeration), message);
} else if (!this.isFromChatOp) {
// HASHTABLE KEY WILL BE NICKNAME STORED IN COOKIE REF BY ChatGlobals.CHAT_COOKIE_NAME
CookieRetriever cr = new CookieRetriever("http://" + ChatGlobals.SERVER_NAME +
ChatGlobals.SCRIPT_PATH + "/" +
ChatGlobals.COOKIE_GRABBER_FILENAME,
ChatGlobals.CHAT_COOKIE_NAME);
messageHash.put(cr.getCookieVal(), message);
} else {
// HASHTABLE KEY WILL BE STATIC VALUE OF ChatGlobals.CHAT_BRAND_NAME
messageHash.put(ChatGlobals.CHAT_BRAND_NAME, message);
}
return messageHash;
}
Ok, so at this point we went like this:
1) MessageProcessor passes an Enumeration to MessageBinHashBundler cast as an Object
2) MessageBinHashBundler pass an Object to CookieRetriever
Here is CookieRetriever.getCookieVal(boolean willUseEnumeration)
/**
* Retrieve cookie value from HttpServletRequest request.getHeaders("Cookie") which spawned the Enumeration obj parameter
*
* @access public
* @param boolean willUseEnumeration
* @return String name of cookie
*/
public String getCookieVal(boolean willUseEnumeration) {// STRING METHOD
String cookieText = "";
int index = 0;
if (willUseEnumeration && this.enumm != null) {
Enumeration e = (Enumeration)this.enumm;
cookieText = (String)e.nextElement();
while (e.hasMoreElements()) {
cookieText = (String)e.nextElement();
index = cookieText.indexOf("=");
if (index > -1 && cookieText != null && cookieText.substring(0, index).trim().equals(this.cookieName))
return cookieText.substring(index + 1);
}
return "blah";
} else {
// GO BACK TO URL-SCRAPING-BASED getCookieVal() METHOD
return this.getCookieVal();
}
}
And yet, even after:
3) CookieRetriever sets a local Enumeration "e" as the Enumeration-casted Object value of this.enumm
e.hasMoreElements() is always false! Even when the original boolean return value all the way back from MessageProcessor was true!
So at this point I'm just plain out of ideas. I'm open, sorry, help!
Phil
I got it to work after a week of trying, but I simply will never understand why it works.
First of all, I'm passing the cookie info via java.util.Hashtable now, so that's much easier for me to understand.. and..
When you send a message to be added to the messages file, it's supposed to prepend onto the message "[your cookie value i.e. your nickname]>", e.g. "James>" or "Phil>" or "Whoever>", and then your message, which gets displayed.
That is the sole purpose of the class MessageBinHashBundler, which takes that.
The file "chat_submit_message.jsp" will submit your message to the messages file. Here is how it originally worked:
1) It would data scrape the servlet "ChatServlet" with query string "?message=" + URLEncoder.encode(message, "UTF-8") + "&nickname=" + URLEncoder.encode(cookie, "UTF-8")
2) The servlet would instantiate a MessageProcessor object which would perform its process() method, call up MessageBinHashBundler, combine the message into the "Phil> blah blah blah" message format and place it into the message file.
Problem is, [1] never worked inasmuch as you'd never see "Phil> blah blah blah" you would insted see "> blah blah blah" because the cookie "stopped existing" for some unknown reason.
So what I did was something I looked up online that worked. Instead of data scraping the servlet to call up MessageProcessor object, I called it directly after performing request.setAttribute():
request.setAttribute("message", (Object)URLEncoder.encode(message, "UTF-8"));
request.setAttribute("nickname", (Object)URLEncoder.encode(cookie, "UTF-8"));
MessageProcessor mp = new MessageProcessor(request, response);
mp.process();
When I use THIS code in chat_submit_message.jsp, sure enough, ultimately in the message file, I see "Phil> blah blah blah" or "Whoever> blah blah blah" the way it should be.
In short, it works and I can't possibly explain why.
Phil
