Home > Archive > Java Help > January 2006 > Re: How could this possibly happen (HttpURLConnection + simple JSP
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Re: How could this possibly happen (HttpURLConnection + simple JSP
|
|
| James Westby 2006-01-24, 7:05 pm |
| phillip.s.powell@gmail.com wrote:
> 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.
[snip]
How's this code. One import, no second request, no "scraping", no
javax.servlet.http.Cookie, no messing.
<HTML><HEAD><TITLE>TEST</TITLE></HEAD><BODY>
<%@ page import="java.util.Enumeration" %>
Cookies: <% Enumeration e = request.getHeaders("Cookie");
while (e.hasMoreElements()) {
String cookie = (String)e.nextElement();
int index = cookie.indexOf("=");
if (index > -1) {
out.println("Name:
"+cookie.substring(0,index)+"<br>");
out.println("Value:
"+cookie.substring(index+1)+"<br><br
>");
} else {
out.println("Error<br>");
}
}
%>
<% response.setHeader("Set-Cookie", "name=Bob"); %>
</BODY></HTML>
The first load of the page will show just Cookie:
The second should show the name value pairs of the cookie that was set
the first time.
Considerably less code than you were trying to write, and no headaches.
James
| |
| James Westby 2006-01-24, 7:06 pm |
| phillip.s.powell@gmail.com wrote:
> Looks a lot simpler than what I came up with, but I'm notorious for
> coming up with the most complex solution to things and having to have
> others make it simpler for me as I never think of it myself *sigh*
Not particularly difficult to come up with if you understand what a
cookie is. It was suggested as teh first response to your post.
>
> However, I do have one question: Why do you have response.setHeader()
> embedded within the HTML code? In PHP that would throw some nasty
> HTTP-related warnings and potentially break the page as you are
> changing the headers after HTML display?
I think you need to look again at the architecture of JSP pages.
You are not really writing HTML pages. You are writing code in a special
format that is compiled in to a servlet, which is then executed by the
server when the page is requested.
The other thing is that writing things "after HTML display" is probably
very difficult as the display is done on the users computer when they
have recieved the response.
You know you have some predefined variables in JSP pages, request,
response, out. You get the request so that you know what the user wants.
You get the response so that you can return this to them. out is merely
the object returned by response.getOutputStream(). You know that the
response has two sections, a header and body, and when you call
out.println() you put stuff in the body. When you call setHeader() you
put stuff in the header. Think of all the HTML you write in a page as
being wrapped up in out.println(). I guess you understand all this, but
worth clarifying for the next bit.
When you create a response for the user it does not necessarily get sent
back as soon as you start, and more importantly the headers do not
necessarily finish as soon as you start writing to the body. This allows
you to manipulate the headers whenever you want, which can be convinient.
My guess is that this is different in PHP then, do you have to do all
header stuff at the top of a page or something? If so then it will
finish the headers in the reponse the moment you manipulate the body.
Obviously this works fine in some cases, but could make some things
difficult. I have seen PHP pages where one page is chopped up in to
multiple fragments, how would you maipulate the headers in a fragment
further down? I don't like this pattern at all, for one it makes the
code almost impossible to read. I've seen mention of a Java thing called
sitemesh somewhere that allows you to do something similar, but all the
chunks are valid bits of HTML, and so it is much less confusing, but it
may still have problems, I haven't used it so I don't know.
Hope you get all your problems sorted.
James
| |
| James Westby 2006-01-24, 7:06 pm |
| Oliver Wong wrote:
> "James Westby" <jw2328@bris.ac.uk> wrote in message
> news:q4tBf.179198$D47.137267@fe3.news.blueyonder.co.uk...
>
[snip][color=darkred]
> In PHP, the default is as you've guessed: As soon as some body content
> is sent, it is an error to then try to emit header content. However, it is
> possible to set up your PHP environment so that output is buffered, to make
> it behave like JSPs as described above in the first paragraph of yours that
> I've quoted.
>
> In PHP, there's a lot of "you don't know how the envrionment is set up"
> (unlike Java), so a common practice is to build up the page in a string, and
> then, at the very end, emit all the headers, and then the entire body at
> once, essentially implementing buffered output manually, so that you don't
> need to rely on the environment being set up to buffer output automatically.
>
Thanks for the clarification.
James
| |
| James Westby 2006-01-25, 7:57 am |
| phillip.s.powell@gmail.com wrote:
> I'll try that next, although you must understand why I simply can't
> fathom how you can do that..
>
> Meanwhile you had given me an 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:
>
[snip]
>
> 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.
>
There's no need to worry about passing it as a serializable object when
you are merely calling functions. Pass it as an enumeration to take
better advantage of Java's type safety.
> So now we're in MessageBinHashBundler:
>
[snip]
>
> 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
>
OK
> Here is CookieRetriever.getCookieVal(boolean willUseEnumeration)
>
> code:
> /**
> * 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();
You have pulled out the first element before you start the loop. This is
a bad idea. For one you will get an exception if e has no elements. For
another the first element will always be skipped. Lastly if there is
only one element you will never do anything with the enumeration. have
another look at my sample code.
> 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();
You are falling back to a method that you know doesn't work? Or is it
working now? Or is this just here as you are modifying your code?
> }
> }
>
>
> 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!
Because you have removed the only element before you call it.
>
> So at this point I'm just plain out of ideas. I'm open, sorry, help!
Hope this fixes it.
James
| |
| James Westby 2006-01-25, 7:16 pm |
| James Westby wrote:[color=darkred]
> phillip.s.powell@gmail.com wrote:
>
[snip]
Improved code:
<HTML><HEAD><TITLE>TEST</TITLE></HEAD><BODY>
<%@ page import="java.util.Enumeration, javax.servlet.http.Cookie" %>
<% Enumeration e = request.getHeaders("Cookie");
if (e!=null) {
while (e.hasMoreElements()) {
String cookie = (String)e.nextElement();
int eqIndex = cookie.indexOf("=");
int semiIndex = cookie.indexOf(";");
while (eqIndex > -1 && semiIndex > -1) {
out.println("Cookie: Name:
"+cookie.substring(0,eqIndex)+"<br>");
out.println("Value:
"+cookie.substring(eqIndex+1, semiIndex)+"<br><br>");
cookie = cookie.substring(semiIndex+1);
eqIndex = cookie.indexOf("=");
semiIndex = cookie.indexOf(";");
}
}
} else {
out.println("No Cookies");
}
%>
<% response.addHeader("Set-Cookie", "name=Bob"); %>
<% response.addHeader("Set-Cookie", "flib=flob"); %>
</BODY></HTML>
This code deals with multiple cookies properly. Before it would only
print the first cookie for browsers that send all cookies in one Header
(firefox).
It also uses addHeader to set cookies, to prevent only one being set
(with setHeader). This is perfectly valid from what I have read.
James
| |
| James Westby 2006-01-25, 7:16 pm |
| Oliver Wong wrote:
[snip]
>
> I see you're getting the Enumeration from
> this.request.getHeaders("Cookie"). I don't know what the "getHeaders" method
> does, but its name implies that it will return a collection of headers,
> rather than an enumeration over the collection of headers. Is that method
> part of some library, or did you write it yourself?
>
getHeaders
public java.util.Enumeration getHeaders(java.lang.String name)
Returns all the values of the specified request header as an
Enumeration of String objects.
Some headers, such as Accept-Language can be sent by clients as
several headers each with a different value rather than sending the
header as a comma separated list.
If the request did not include any headers of the specified name,
this method returns an empty Enumeration. The header name is case
insensitive. You can use this method with any request header.
Parameters:
name - a String specifying the header name
Returns:
a Enumeration containing the values of the requested header, or
null if the request does not have any headers of that name
(from javax.servlet.http.HttpServletRequest Javadoc at
http://java.sun.com/products/servlet/2.2/javadoc/)
James
| |
| James Westby 2006-01-25, 7:16 pm |
| phillip.s.powell@gmail.com wrote:
[snip]
>
>
> And also doesn't work. (String)e.nextElement() is always "" regardless
> of what it was intitially.
[snip]
What do you mean "what it was originally"?
How are you setting your cookie values?
James
| |
| James Westby 2006-01-26, 7:05 pm |
| phillip.s.powell@gmail.com wrote:
[snip]
I'll rephrase my question.
What do you mean "what it was initially"?
[color=darkred]
>
>
> I initially set my cookie values in chat_validation.jsp:
>
> code:
> response.addCookie(new Cookie(ChatGlobals.CHAT_COOKIE_NAME,
> (Object)request.getParameter("nick")));
>
The constructor of Cookie takes two Strings, not a String and an Object
(assuming CHAT_COOKIE_NAME is a String). Does this code compile?
>
> And then redirect to chat.jsp. If that's what you mean. Otherwise I'm
> not sure what you mean.
And are you expecting to see the Cookie first time?
How are you doing the redirection?
James
| |
| James Westby 2006-01-26, 7:06 pm |
| phillip.s.powell@gmail.com wrote:
> Maybe it's best to skip this and let you know that last night I got it
> to work after a w of trying, but I simply will never understand why
> it works.
>
> 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():
>
> code:
> 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
Well done.
James
|
|
|
|
|