Consegui fazer alguns progressos!
Criei uma html inicial que possui um formulário com um campo de texto onde o usuário informar a url. Ao enviar esse formulário, o servlet abaixo busca a página usando as classes URL e URLConnection. Então eu uso a biblioteca Jsoup para alterar os atributos HREF e SRC de todos os elementos DOM que estejam como relativo para absoluto (usando como base a url informada pelo usuário). Isso faz com que imagens, scripts e css sejam baixados do servidor certo, e não do meu servidor.
Segue o código-fonte do servlet:
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URL;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public class TunelServlet extends HttpServlet {
private static final long serialVersionUID = -4675061985025674960L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Busca a página informada pelo usuário, pegando o html e escrevendo-o
// como sendo do meu servidor.
carregarPagina(request.getParameter("url"), response);
}
private void carregarPagina(String url, HttpServletResponse response) {
response.setContentType("text/html");
try {
URL pagina = new URL(url);
PrintWriter out = response.getWriter();
// Pega o html da página solicitada, fazendo um "parse" para que
// os elementos DOM possam ser extraídos e acessados.
Document doc = Jsoup.parse(pagina, 3*1000);
// Navega por cada elemento DOM da página...
for (Element e : doc.children()) {
// Se o elemento possuir os atributos HREF e/ou SRC usando
// caminhos relativos, esses atributos são alterados para
// usarem o caminho absoluto.
relativoParaAbsoluto(e);
}
// Escreve o html alterado da página solicitada como se
// fosse uma página do meu servidor.
out.println(doc.outerHtml());
} catch (Exception e) {
e.printStackTrace();
}
}
private void relativoParaAbsoluto(Element e) {
// Se o elemento possuir outros elementos filhos...
for (Element c : e.children()) {
// Chama a mesma função para cada um dos elementos filhos.
relativoParaAbsoluto(c);
}
// Se o elementos possuir o atributo HREF, altera o caminho para
// absoluto.
if (e.attr("href") != "")
e.attr("href", e.absUrl("href"));
// Se o elementos possuir o atributo HREF, altera o caminho para
// absoluto.
if (e.attr("src") != "")
e.attr("src", e.absUrl("src"));
}
}
Ainda falta implementar um forma de redirecionar as requisições de formulários da página carregada para o seu servidor de origem e escrever os resultados como sendo do meu servidor (posso usar o mesmo método usado quando o usuário solicita a página pela primeira vez).
Mas estou com um problema que ainda não sei como resolver:
Eu consegui fazer com que as imagens, scripts externos e css’s externos fossem baixados corretamente pelo browser do usuário (usando a biblioteca Jsoap, como explicado acima). Mas quando os elementos html são criados dinamicamente pelo javascript, eu não consegui alterar os caminhos relativos para absolutos. Acho que o Jsoap não consegue fazer isso. Alguém tem alguma sugestão?