/*
* Copyright (C) 2000 - 2011 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://openbd.org/
* $Id: UrlLinkResolver.java 1713 2011-10-05 22:28:59Z alan $
*/
package com.nary.net.http;
import java.io.ByteArrayOutputStream;
/**
* urlUtils
*
* provides methods useful in the context of URLs
*
*/
public class UrlLinkResolver extends Object {
private ByteArrayOutputStream outputStream;
private int stepBackLimit;
public UrlLinkResolver() {
outputStream = new ByteArrayOutputStream();
}
/**
* given a base URL and source URL, return the actual URL got from these 2
*
* @param baseURL
* - the URL got from the <BASE> tag
* @param sourceURL
* - the URL of the current location
*/
public String encode(String baseURL, String sourceURL) {
outputStream.reset();
stepBackLimit = 0;
int nextIndex; // used to hold index of next char in the buffer
// is baseURI relative, or absolute?
// absolute
if (baseURL.startsWith("http://") || baseURL.startsWith("https://")) {
return baseURL;
} else {
// relative
// create combined URL that includes all ./'s and ..'s
String fullURL;
// if base url is a root url
if (baseURL.startsWith("/") || baseURL.startsWith("\\")) {
// combine the 2 urls - taking the source uri from the start to the third
// '/'
fullURL = (sourceURL.substring(0, (sourceURL.indexOf('/', 7))) + baseURL).replace('\\', '/');
} else {
// else just combine the 2 urls - source first so the combined str = http....
fullURL = (sourceURL + baseURL).replace('\\', '/');
}
byte[] urlCopy = fullURL.getBytes();
// System.out.println("Full URL : " + new String(urlCopy));
int index = 0;
index = readNext(urlCopy, index); // read 'http:/'
index = readNext(urlCopy, index); // read '/'
index = readNext(urlCopy, index); // read up to next '/' -- this is the step back limit
stepBackLimit = index - 1; // this is the place where you cannot .. back anymore
while (index < urlCopy.length) {
nextIndex = index + 1;
if (urlCopy[index] == '.') {
if (nextIndex == urlCopy.length) {
// if there are no more chars
index++;
} else if (urlCopy[nextIndex] == '/') {
// else if currently looking at "./" then ignore it (i.e. don't write it
// to the output stream
index = nextIndex + 1; // move to next char after the "./"
} else if (urlCopy[nextIndex] == '.') {
// else if currently looking at ".." then need to step back a directory
// in the url
stepBack();
index = nextIndex + 2; // move to next char after the ".."
} else {
index++;
}
} else if (urlCopy[index] == '/') {
// else if currently looking at "//" then ignore the 2nd /
index = index + 1; // move to next char after the "//"
} else {
index = readNext(urlCopy, index);
}
}// while
}
return new String(outputStream.toString());
}
/**
* read the next part of the URL into the byteArrayOutputStream. start the read from position 'start' in 'buffer'
*/
private int readNext(byte[] buffer, int start) {
int currIndex = start;
while (currIndex < buffer.length && buffer[currIndex] != '/') {
outputStream.write(buffer[currIndex]);
currIndex++;
}
if (currIndex != buffer.length) {
outputStream.write(buffer[currIndex]);
currIndex++;
}
return currIndex;
}
private void stepBack() {
// convert current stored url to byte[]
byte[] temp = outputStream.toByteArray();
// if can't step back anymore
if (temp.length - 1 == stepBackLimit) {
return;
}
// reset the output stream. going to copy back part of temp at the end
outputStream.reset();
// move back to before the current '/'
int currIndex = temp.length - 2;
while ((currIndex > stepBackLimit) && temp[currIndex] != '/') {
currIndex--;
}
if (currIndex == stepBackLimit) {
// stepBackLimit reached
for (int i = 0; i <= stepBackLimit; i++) {
outputStream.write(temp[i]);
}
} else {
for (int j = 0; j <= currIndex; j++) {
outputStream.write(temp[j]);
}
}
}// stepBack
}