/*
* Copyright 2000-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jetspeed.services.webpage;
// java.io
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
/*
* Abstract Base class for web page sessions. Implements the primary dispatcher
* logic for getting and posting resources.
*
*/
public abstract class AbstractSiteSession implements SiteSession {
// the base url of the host being proxied
protected String targetBase;
// the base url the wps
protected String proxyBase;
// the cookies collection
protected HashMap cookies = new HashMap();
// counters
protected int hitCount = 0;
protected int cacheCount = 0;
// the log file singleton instance
static Logger log = Logger.getLogger(AbstractSiteSession.class);
/**
* Create a NetElementSession, which maintains sessions with one network
* element.
*
* @param targetBase
* the target host's base URL
* @param proxyBase
* the proxy server host URL base address.
*/
public AbstractSiteSession(String targetBase, String proxyBase) {
this.proxyBase = proxyBase;
this.targetBase = targetBase;
}
/**
* Given a URL, returns the content from that URL in a string. All HTTP
* hyperlinks(HREFs) are rewritten as proxied-referenced hyperlinks. All
* relative references to web resources (images, stylesheets, ...) are
* rewritten as absolute references, but are not proxied. Determines if we are
* logged on to the target site. If not, calls logon(), which is a
* implementation specific 'POST' exchange
*
* @see logon(String, HttpServletRequest, HttpServletResponse)
*
* @param url
* the proxied resource address.
* @param data
* the rundata
*
* @exception IOException
* a servlet exception.
*/
public void dispatch(String url, ProxyRunData data) throws IOException {
try {
Configuration config = Configuration.getInstance();
log.debug("=== Dispatching =" + url);
// open a pooled HTTP connection
// URL u = new URL(url);
URL u = new URL(null, url);
HttpURLConnection con = (HttpURLConnection) u.openConnection();
// if (con instanceof HttpURLConnection)
con.setDoInput(true);
con.setDoOutput(true);
con.setAllowUserInteraction(false);
con.setFollowRedirects(false);
if (data.getPosting()) {
con.setRequestMethod("POST");
}
// are there any cookies in our current session?
if (cookies.isEmpty()) {
// there are no cookies, must be a new session, so lets logon
log.debug("... no session id provided. Logging on...");
if (false == logon(data)) {
return;
}
}
// send the cookies (session ids) back to the NE
Iterator it = cookies.values().iterator();
Cookie cookie;
while (it.hasNext()) {
cookie = (Cookie) it.next();
String sessionID = WebPageHelper.buildCookieString(cookie);
con.setRequestProperty("Cookie", sessionID);
log.debug("... Sending Session ID: " + sessionID);
}
// we have to get the post parameters from the servlet container,
// and then re-encode them. i wish i could find out how to keep
// the servlet container from reading them, because now i have to
// parse them out, and then re-encode
if (data.getPosting()) {
// get the post params
StringBuffer postParams = new StringBuffer();
int count = 0;
Enumeration e = data.getRequest().getParameterNames();
while (e.hasMoreElements()) {
String name = (String) e.nextElement();
if (name.equals(config.getSID()) || name.equals(config.getURL())) {
continue;
}
String values[] = data.getRequest().getParameterValues(name);
if (values != null) {
for (int i = 0; i < values.length; i++) {
if (count > 0) {
postParams.append("&");
}
postParams.append(name);
postParams.append("=");
postParams.append(URLEncoder.encode(values[i]));
count++;
}
}
}
String postString = postParams.toString();
con.setRequestProperty("Content-length", String.valueOf(postString
.length()));
// write directly to the output stream
DataOutputStream dos = new DataOutputStream(con.getOutputStream());
log.debug("... POST: " + postString);
dos.writeBytes(postString);
dos.close();
}
int rc = con.getResponseCode();
// Get the Session Information from Headers
int contentType =
WebPageHelper.getContentType(con.getHeaderField("content-type"), u
.toString());
String location = con.getHeaderField("Location");
if ((rc == con.HTTP_MOVED_PERM || rc == con.HTTP_MOVED_TEMP)
&& null != location) {
log.debug("+++ REDIRECT = " + location);
location = WebPageHelper.concatURLs(targetBase, location);
dispatch(location, data);
return;
}
// get cookies set from server
String cookieString = con.getHeaderField("Set-Cookie");
if (null != cookieString) {
log.debug("... new SessionID found: " + cookieString);
WebPageHelper.parseCookies(cookieString, this);
}
if (contentType == WebPageHelper.CT_IMAGE
|| contentType == WebPageHelper.CT_BINARY
|| contentType == WebPageHelper.CT_APPLICATION) {
// wasn't in the cache, get it from host
getBinaryContent(con, data.getResponse());
return;
}
rewriteContent(data, con, contentType, url);
} catch (IOException ex) {
log.error("*** PROXY DISPATCH EXCEPTION = " + ex);
throw ex;
}
}
/**
* Gets the HTML content from the URL Connection stream and returns it in a
* string
*
* @param con
* The URLConnection to read from.
* @param resource
* The full URL of the resource.
* @return The HTML Content from the stream.
*
* @exception IOException
* a servlet exception.
*/
public String getHTMLContent(URLConnection con, ProxyRunData data,
String resource) throws IOException {
int CAPACITY = 4096;
InputStream is = con.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
Configuration config = Configuration.getInstance();
FileOutputStream fos = null;
boolean logging = config.getEnableContentLog();
if (logging) {
if (data != null) {
String fileName =
data.getServlet().getServletContext().getRealPath(
config.getLogLocation());
fos = new FileOutputStream(fileName, true);
WebPageHelper.writeHeader(fos, resource);
}
}
// now process the InputStream...
byte[] bytes = new byte[CAPACITY];
int readCount = 0;
int total = 0;
while ((readCount = is.read(bytes)) > 0) {
buffer.write(bytes, 0, readCount);
if (logging) {
fos.write(bytes, 0, readCount);
}
total += readCount;
}
if (logging) {
fos.close();
}
is.close();
return buffer.toString();
}
/**
* Gets the HTML content from the URL Connection stream and writes it to
* respones
*
* @param con
* The URLConnection to read from.
*
* @exception IOException
* a servlet exception.
*/
public void getBinaryContent(URLConnection con, HttpServletResponse response)
throws IOException {
int CAPACITY = 4096;
InputStream is = con.getInputStream();
// FileOutputStream fos = new FileOutputStream("/test.fw", true);
// now process the InputStream...
byte[] bytes = new byte[CAPACITY];
int readCount = 0;
while ((readCount = is.read(bytes)) > 0) {
response.getOutputStream().write(bytes, 0, readCount);
// fos.write( bytes, 0, readCount);
}
// fos.close();
is.close();
}
/**
* Given a cookie, it first checks to see if that cookie is already managed in
* this session. If it is, it means that the session has timed out and that
* the network element has now created a new session. In that case, replace
* the cookie, and re-establish the session (logon) If its a new cookie, we
* will still need to logon, and and the cookie to the managed cookies
* collection for this session.
*
* @param cookie
* new cookie returned from target server.
* @return true when a new cookie added, false when updated.
*
*/
public boolean addCookieToSession(Cookie cookie) {
boolean added = (null == cookies.get(cookie.getName()));
cookies.put(cookie.getName(), cookie); // adds or updates
return added;
}
/*
* Gets the hitcount for this session.
*
* @return the hitcount for this session.
*/
public int getHitCount() {
return hitCount;
}
/*
* Increments the hitcount for this session.
*
*/
public void incHitCount() {
hitCount++;
}
/*
* Gets the cache count for this session.
*
* @return the cache count for this session.
*/
public int getCacheCount() {
return cacheCount;
}
/*
* Increments the hitcount for this session.
*
*/
public void incCacheCount() {
cacheCount++;
}
}