blob: 9d58eb0436aafbb2bcf1ced5045f3923ee362a17 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.cocoon.portal.reading;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Response;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.portal.coplet.CopletInstanceData;
import org.apache.cocoon.portal.transformation.ProxyTransformer;
import org.apache.cocoon.reading.ServiceableReader;
import org.apache.cocoon.util.NetUtils;
import org.xml.sax.SAXException;
/**
* This reader is used to retrieve non XML content from external applications
* routet via the portal site. Requests from external resources are marked with
* a proxy prefix and have coplet id and portal name attached as request
* parameters. The portal name and coplet id are used to look up necessary
* connection data for the external request (like session id, cookies,
* document base, etc.) from the application coplet instance data.
*
* @author <a href="mailto:gernot.koller@rizit.at">Gernot Koller</a>
* @author <a href="mailto:friedrich.klenner@rzb.at">Friedrich Klenner</a>
*
* @version CVS $Id$
*/
public class ProxyReader extends ServiceableReader {
/**
* The coplet instance data
*/
protected CopletInstanceData copletInstanceData;
/**
* The HTTP response
*/
protected Response response;
/**
* The origninal HTTP request
*/
protected Request request;
/** The prefix */
protected String prefix;
/**
* @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(SourceResolver, Map, String, Parameters)
*/
public void setup(SourceResolver resolver,
Map objectModel,
String src,
Parameters par)
throws ProcessingException, SAXException, IOException {
super.setup(resolver, objectModel, src, par);
request = ObjectModelHelper.getRequest(objectModel);
response = ObjectModelHelper.getResponse(objectModel);
String copletID = request.getParameter(ProxyTransformer.COPLETID);
String portalName = request.getParameter(ProxyTransformer.PORTALNAME);
copletInstanceData =
ProxyTransformer.getInstanceData(
this.manager,
copletID,
portalName);
this.prefix = par.getParameter("prefix", ProxyTransformer.PROXY_PREFIX);
}
/**
* @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
*/
public void recycle() {
this.response = null;
this.request = null;
this.copletInstanceData = null;
super.recycle();
}
/**
* Send the request to the external WebServer
* @throws IOException on any exception that occures
* @see org.apache.cocoon.reading.Reader#generate()
*/
public void generate() throws IOException {
String link = request.getRequestURI();
link = link.substring(link.indexOf(this.prefix) + this.prefix.length());
String documentBase =
(String) copletInstanceData.getAttribute(
ProxyTransformer.DOCUMENT_BASE);
String remoteURI = null;
remoteURI = ProxyTransformer.resolveURI(link, documentBase);
HttpURLConnection connection = connect(request, remoteURI);
copyHeaderFields(connection, response);
sendData(connection.getInputStream());
}
/**
* Copy the data to the original response stream
* @param in the response from external request to read from
* @throws IOException on any exception
*/
protected void sendData(InputStream in) throws IOException {
int length = -1;
byte[] buf = new byte[4096];
while ((length = in.read(buf)) > -1) {
out.write(buf, 0, length);
}
out.flush();
in.close();
}
/**
* Establish the HttpURLConnection to the given uri.
* @param request the original request
* @param uri the remote uri
* @return the established HttpURLConnection
* @throws IOException on any exception
*/
protected HttpURLConnection connect(Request request, String uri)
throws IOException {
String cookie =
(String) copletInstanceData.getAttribute(ProxyTransformer.COOKIE);
Enumeration enumeration = request.getParameterNames();
boolean firstattribute = true;
StringBuffer query = new StringBuffer();
while (enumeration.hasMoreElements()) {
String paramName = (String) enumeration.nextElement();
if (!paramName.startsWith("cocoon-portal-")) {
String[] paramValues = request.getParameterValues(paramName);
for (int i = 0; i < paramValues.length; i++) {
if (firstattribute) {
query.append('?');
firstattribute = false;
}
else {
query.append('&');
}
query.append(NetUtils.encode(paramName, "utf-8"));
query.append('=');
query.append(NetUtils.encode(paramValues[i], "utf-8"));
}
}
}
uri = uri + query.toString();
URL url = new URL(uri);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects(true);
if (cookie != null) {
connection.setRequestProperty(ProxyTransformer.COOKIE, cookie);
}
connection.connect();
copletInstanceData.setAttribute(
ProxyTransformer.COOKIE,
connection.getHeaderField(ProxyTransformer.COOKIE));
return connection;
}
/**
* Copy header fields from external response to original response.
* @param connection the connection to the external resource
* @param response the original HTTP response.
*/
private void copyHeaderFields(
HttpURLConnection connection,
Response response) {
String[] fieldNames =
new String[] {
"Content-Range",
"Accept-Ranges",
"Content-Length",
"Last-Modified",
"Content-Type",
"Expires" };
for (int i = 0; i < fieldNames.length; i++) {
String value = connection.getHeaderField(fieldNames[i]);
if (value != null) {
response.setHeader(fieldNames[i], value);
}
}
}
}