You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ta...@apache.org on 2013/11/05 02:26:22 UTC
git commit: More complete URL handling and tests.
Updated Branches:
refs/heads/trunk a19bec7b2 -> 8db1d9ae2
More complete URL handling and tests.
Project: http://git-wip-us.apache.org/repos/asf/activemq-cpp/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-cpp/commit/8db1d9ae
Tree: http://git-wip-us.apache.org/repos/asf/activemq-cpp/tree/8db1d9ae
Diff: http://git-wip-us.apache.org/repos/asf/activemq-cpp/diff/8db1d9ae
Branch: refs/heads/trunk
Commit: 8db1d9ae25a6df071ab6747c461357f0b3c1e67b
Parents: a19bec7
Author: Timothy Bish <ta...@gmai.com>
Authored: Mon Nov 4 20:26:09 2013 -0500
Committer: Timothy Bish <ta...@gmai.com>
Committed: Mon Nov 4 20:26:09 2013 -0500
----------------------------------------------------------------------
activemq-cpp/src/main/Makefile.am | 2 +
.../src/main/decaf/internal/net/URLUtils.cpp | 140 +++++++++
.../src/main/decaf/internal/net/URLUtils.h | 122 ++++++++
activemq-cpp/src/main/decaf/lang/String.cpp | 136 +++++----
activemq-cpp/src/main/decaf/lang/String.h | 25 +-
activemq-cpp/src/main/decaf/net/URL.cpp | 21 +-
.../src/main/decaf/net/URLStreamHandler.cpp | 81 ++---
activemq-cpp/src/test/decaf/lang/StringTest.cpp | 157 +++++++++-
activemq-cpp/src/test/decaf/lang/StringTest.h | 14 +-
activemq-cpp/src/test/decaf/net/URLTest.cpp | 306 ++++++++++++++++++-
activemq-cpp/src/test/decaf/net/URLTest.h | 28 ++
11 files changed, 897 insertions(+), 135 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/main/Makefile.am
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/Makefile.am b/activemq-cpp/src/main/Makefile.am
index a9b043c..9a85a5f 100644
--- a/activemq-cpp/src/main/Makefile.am
+++ b/activemq-cpp/src/main/Makefile.am
@@ -354,6 +354,7 @@ cc_sources = \
decaf/internal/net/URIType.cpp \
decaf/internal/net/URLStreamHandlerManager.cpp \
decaf/internal/net/URLType.cpp \
+ decaf/internal/net/URLUtils.cpp \
decaf/internal/net/file/FileHandler.cpp \
decaf/internal/net/http/HttpHandler.cpp \
decaf/internal/net/ssl/DefaultSSLContext.cpp \
@@ -1031,6 +1032,7 @@ h_sources = \
decaf/internal/net/URIType.h \
decaf/internal/net/URLStreamHandlerManager.h \
decaf/internal/net/URLType.h \
+ decaf/internal/net/URLUtils.h \
decaf/internal/net/file/FileHandler.h \
decaf/internal/net/http/HttpHandler.h \
decaf/internal/net/ssl/DefaultSSLContext.h \
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/main/decaf/internal/net/URLUtils.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/internal/net/URLUtils.cpp b/activemq-cpp/src/main/decaf/internal/net/URLUtils.cpp
new file mode 100644
index 0000000..6ca05c9
--- /dev/null
+++ b/activemq-cpp/src/main/decaf/internal/net/URLUtils.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+#include <decaf/internal/net/URLUtils.h>
+
+using namespace decaf;
+using namespace decaf::lang;
+using namespace decaf::net;
+using namespace decaf::internal;
+using namespace decaf::internal::net;
+
+////////////////////////////////////////////////////////////////////////////////
+URLUtils::URLUtils() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String URLUtils::getHost(const URL& url) {
+ String host = url.getHost();
+ if (url.getProtocol().equals("file") && host.isEmpty()) {
+ return "localhost";
+ }
+ return host;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String URLUtils::canonicalizePath(const String& original, bool discardRelativePrefix) {
+
+ String path = original;
+
+ // the first character of the current path segment
+ int segmentStart = 0;
+
+ // the number of segments seen thus far that can be erased by sequences of '..'.
+ int deletableSegments = 0;
+
+ for (int i = 0; i <= path.length(); ) {
+ int nextSegmentStart;
+ if (i == path.length()) {
+ nextSegmentStart = i;
+ } else if (path.charAt(i) == '/') {
+ nextSegmentStart = i + 1;
+ } else {
+ i++;
+ continue;
+ }
+
+ /*
+ * We've encountered either the end of a segment or the end of the
+ * complete path. If the final segment was "." or "..", remove the
+ * appropriate segments of the path.
+ */
+ if (i == segmentStart + 1 && path.regionMatches(segmentStart, ".", 0, 1)) {
+ // Given "abc/def/./ghi", remove "./" to get "abc/def/ghi".
+ path = path.substring(0, segmentStart) + path.substring(nextSegmentStart);
+ i = segmentStart;
+ } else if (i == segmentStart + 2 && path.regionMatches(segmentStart, "..", 0, 2)) {
+ if (deletableSegments > 0 || discardRelativePrefix) {
+ // Given "abc/def/../ghi", remove "def/../" to get "abc/ghi".
+ deletableSegments--;
+ int prevSegmentStart = path.lastIndexOf('/', segmentStart - 2) + 1;
+ path = path.substring(0, prevSegmentStart) + path.substring(nextSegmentStart);
+ i = segmentStart = prevSegmentStart;
+ } else {
+ // There's no segment to delete; this ".." segment must be retained.
+ i++;
+ segmentStart = i;
+ }
+ } else {
+ if (i > 0) {
+ deletableSegments++;
+ }
+ i++;
+ segmentStart = i;
+ }
+ }
+ return path;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String URLUtils::authoritySafePath(const String& authority, const String& path) {
+ if (!authority.isEmpty() && !path.isEmpty() && !path.startsWith("/")) {
+ return String("/") + path;
+ }
+ return path;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool URLUtils::isValidSchemeChar(int index, char c) {
+
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ return true;
+ }
+ if (index > 0 && ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')) {
+ return true;
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+String URLUtils::getSchemePrefix(const String& spec) {
+ int colon = spec.indexOf(':');
+
+ if (colon < 1) {
+ return String();
+ }
+
+ for (int i = 0; i < colon; i++) {
+ char c = spec.charAt(i);
+ if (!isValidSchemeChar(i, c)) {
+ return String();
+ }
+ }
+
+ return spec.substring(0, colon).toLowerCase();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+int URLUtils::findFirstOf(const String& string, const String& chars, int start, int end) {
+ for (int i = start; i < end; i++) {
+ char c = string.charAt(i);
+ if (chars.indexOf(c) != -1) {
+ return i;
+ }
+ }
+ return end;
+}
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/main/decaf/internal/net/URLUtils.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/internal/net/URLUtils.h b/activemq-cpp/src/main/decaf/internal/net/URLUtils.h
new file mode 100644
index 0000000..b75cfb7
--- /dev/null
+++ b/activemq-cpp/src/main/decaf/internal/net/URLUtils.h
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#ifndef _DECAF_INTERNAL_NET_URLUTILS_H_
+#define _DECAF_INTERNAL_NET_URLUTILS_H_
+
+#include <decaf/util/Config.h>
+#include <decaf/lang/String.h>
+#include <decaf/net/URL.h>
+
+namespace decaf {
+namespace internal {
+namespace net {
+
+ class DECAF_API URLUtils {
+ private:
+
+ URLUtils();
+
+ public:
+
+ /**
+ * File based URL instance with an empty host value are always considered
+ * to have a host value of "localhost".
+ *
+ * @param url
+ * the URL whose host value is to be returned.
+ *
+ * @returns the host value or 'localhost' for file based protocols.
+ */
+ static decaf::lang::String getHost(const decaf::net::URL& url);
+
+ /**
+ * Returns the path will relative path segments like ".." and "." resolved.
+ * The returned path will not necessarily start with a "/" character. This
+ * handles ".." and "." segments at both the beginning and end of the path.
+ *
+ * @param discardRelativePrefix
+ * true to remove leading ".." segments from the path. This is appropriate
+ * for paths that are known to be absolute.
+ *
+ * @returns the canonicalized Path value.
+ */
+ static decaf::lang::String canonicalizePath(const decaf::lang::String& original, bool discardRelativePrefix);
+
+ /**
+ * Returns a path that can be safely concatenated with the given authority. If the
+ * authority is empty, this can be any path. Otherwise the paths run together like
+ * http://activemq.apache.html.
+ *
+ * @param authority
+ * The authority value from a given URL.
+ * @param path
+ * The path value from a given URL.
+ *
+ * @returns a safe version of the Path value.
+ */
+ static decaf::lang::String authoritySafePath(const decaf::lang::String& authority,
+ const decaf::lang::String& path);
+
+ /**
+ * Returns true if the given char is valid for a URL scheme taking into account its
+ * position in the scheme string.
+ *
+ * @param index
+ * The index in the scheme where the char value is from.
+ * @param c
+ * The value from the given index.
+ *
+ * @returns true if the char value is valid for the given index.
+ */
+ static bool isValidSchemeChar(int index, char c);
+
+ /**
+ * Returns the scheme prefix like "http" from the URL spec, or empty if the
+ * spec doesn't start with a scheme. Scheme prefixes match this pattern:
+ * (alpha ( alpha | digit | '+' | '-' | '.' )* ':')
+ */
+ static decaf::lang::String getSchemePrefix(const decaf::lang::String& spec);
+
+ /**
+ * Returns the index of the first char of the given set in the passed in String
+ * bounded between start and end. This returns the end value if none of the characters
+ * exist in the requested range.
+ *
+ * This is an optimization used in URL processing as the return value is end if
+ * the chars are not found in the string so that processing can continue from the
+ * returned end value no matter what the result is.
+ *
+ * @param string
+ * The string to search.
+ * @param chars
+ * The set of characters to search for in the target String.
+ * @param start
+ * The start index to search from.
+ * @param end
+ * The end index to stop the search at.
+ *
+ * @returns the first index that matches one of the chars or the end value if no matches..
+ */
+ static int findFirstOf(const decaf::lang::String& string,
+ const decaf::lang::String& chars, int start, int end);
+
+ };
+
+}}}
+
+#endif /* _DECAF_INTERNAL_NET_URLUTILS_H_ */
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/main/decaf/lang/String.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/lang/String.cpp b/activemq-cpp/src/main/decaf/lang/String.cpp
index eac8eee..7305fd4 100644
--- a/activemq-cpp/src/main/decaf/lang/String.cpp
+++ b/activemq-cpp/src/main/decaf/lang/String.cpp
@@ -45,17 +45,31 @@ namespace lang {
class Contents {
public:
- ArrayPointer<unsigned char> value;
+ ArrayPointer<char> value;
int length;
int offset;
-
int hashCode;
public:
+ /**
+ * Contents as empty string.
+ */
Contents() : value(), length(0), offset(0), hashCode(0) {}
- Contents(int length) : value(length), length(length), offset(0), hashCode(0) {}
- Contents(int offset, int length, ArrayPointer<unsigned char> value) :
+
+ /**
+ * Contents created with the given length, the array is length + 1 to add the
+ * null terminating character.
+ */
+ Contents(int length) : value(length + 1), length(length), offset(0), hashCode(0) {
+ value[length] = 0; // Null terminated
+ }
+
+ /**
+ * Contents is a view of some other String which can either be all or a
+ * window allowing for substring methods to not need to copy the contents.
+ */
+ Contents(int offset, int length, ArrayPointer<char> value) :
value(value), length(length), offset(offset), hashCode(0) {}
};
@@ -63,7 +77,7 @@ namespace lang {
////////////////////////////////////////////////////////////////////////////////
String::String(Contents* content) :
- contents(new Contents(0, content->value.length(), content->value)) {
+ contents(new Contents(0, content->length, content->value)) {
}
////////////////////////////////////////////////////////////////////////////////
@@ -76,6 +90,20 @@ String::String() : contents(new Contents()) {
}
////////////////////////////////////////////////////////////////////////////////
+String::String(const char value, int count) : contents() {
+
+ if (count < 0) {
+ throw IndexOutOfBoundsException(
+ __FILE__, __LINE__, "count parameter out of Bounds: %d.", count);
+ }
+
+ contents = new Contents(count);
+ for (int i = 0; i < count; ++i) {
+ contents->value[i] = value;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
String::String(const String& source) : contents(new Contents(*source.contents)) {
}
@@ -83,11 +111,11 @@ String::String(const String& source) : contents(new Contents(*source.contents))
String::String(const std::string& source) : contents(new Contents((int)source.length())) {
// load the passed string into the contents value.
- System::arraycopy((unsigned char*)source.c_str(), 0, contents->value.get(), 0, source.length());
+ System::arraycopy(source.c_str(), 0, contents->value.get(), 0, source.length());
}
////////////////////////////////////////////////////////////////////////////////
-String::String(const char* array) : contents(new Contents) {
+String::String(const char* array) : contents() {
if (array == NULL) {
throw NullPointerException(
@@ -97,16 +125,15 @@ String::String(const char* array) : contents(new Contents) {
int size = StringUtils::stringLength(array);
if (size > 0) {
-
- this->contents->value = ArrayPointer<unsigned char>(size);
- this->contents->length = size;
-
- System::arraycopy((unsigned char*) array, 0, contents->value.get(), 0, size);
+ this->contents = new Contents(size);
+ System::arraycopy(array, 0, contents->value.get(), 0, size);
+ } else {
+ this->contents = new Contents();
}
}
////////////////////////////////////////////////////////////////////////////////
-String::String(const char* array, int size) : contents(new Contents) {
+String::String(const char* array, int size) : contents() {
if (size < 0) {
throw IndexOutOfBoundsException(
@@ -119,16 +146,15 @@ String::String(const char* array, int size) : contents(new Contents) {
}
if (size > 0) {
-
- this->contents->value = ArrayPointer<unsigned char>(size);
- this->contents->length = size;
-
- System::arraycopy((unsigned char*) array, 0, contents->value.get(), 0, size);
+ this->contents = new Contents(size);
+ System::arraycopy(array, 0, contents->value.get(), 0, size);
+ } else {
+ this->contents = new Contents();
}
}
////////////////////////////////////////////////////////////////////////////////
-String::String(const char* array, int offset, int length) : contents(new Contents) {
+String::String(const char* array, int offset, int length) : contents() {
int size = StringUtils::stringLength(array);
@@ -147,17 +173,16 @@ String::String(const char* array, int offset, int length) : contents(new Content
__FILE__, __LINE__, "Buffer pointer passed was NULL.");
}
- if (size > 0) {
-
- this->contents->value = ArrayPointer<unsigned char>(length);
- this->contents->length = length;
-
- System::arraycopy((unsigned char*) array, offset, contents->value.get(), 0, length);
+ if (size > 0 && length > 0) {
+ this->contents = new Contents(length);
+ System::arraycopy(array, offset, contents->value.get(), 0, length);
+ } else {
+ this->contents = new Contents();
}
}
////////////////////////////////////////////////////////////////////////////////
-String::String(const char* array, int size, int offset, int length) : contents(new Contents) {
+String::String(const char* array, int size, int offset, int length) : contents() {
if (size < 0) {
throw IndexOutOfBoundsException(
@@ -179,12 +204,11 @@ String::String(const char* array, int size, int offset, int length) : contents(n
__FILE__, __LINE__, "Buffer pointer passed was NULL.");
}
- if (size > 0) {
-
- this->contents->value = ArrayPointer<unsigned char>(length);
- this->contents->length = length;
-
- System::arraycopy((unsigned char*) array, offset, contents->value.get(), 0, length);
+ if (size > 0 && length > 0) {
+ this->contents = new Contents(length);
+ System::arraycopy(array, offset, contents->value.get(), 0, length);
+ } else {
+ this->contents = new Contents();
}
}
@@ -210,14 +234,14 @@ String& String::operator= (const String& other) {
////////////////////////////////////////////////////////////////////////////////
String& String::operator= (const std::string& other) {
+ delete contents;
+
if (!other.empty()) {
int length = (int) other.length();
-
- contents->value = ArrayPointer<unsigned char>(length);
- contents->length = length;
- contents->hashCode = 0;
-
- System::arraycopy((unsigned char*)other.c_str(), 0, contents->value.get(), 0, length);
+ contents = new Contents(length);
+ System::arraycopy(other.c_str(), 0, contents->value.get(), 0, length);
+ } else {
+ contents = new Contents();
}
return *this;
@@ -231,12 +255,12 @@ String& String::operator= (const char* other) {
}
int length = StringUtils::stringLength(other);
+ delete contents;
if (length > 0) {
- contents->value = ArrayPointer<unsigned char>(length);
- contents->length = length;
- contents->hashCode = 0;
-
- System::arraycopy((unsigned char*)other, 0, contents->value.get(), 0, length);
+ contents = new Contents(length);
+ System::arraycopy(other, 0, contents->value.get(), 0, length);
+ } else {
+ contents = new Contents();
}
return *this;
@@ -306,11 +330,11 @@ String String::operator+ (const char* other) const {
const char* String::c_str() const {
if (contents->length == 0) {
- return NULL;
+ return "";
}
- if (contents->offset == 0 && contents->length == contents->value.length()) {
- return (const char*) contents->value.get();
+ if (contents->length == contents->value.length() - 1) {
+ return (const char*) (contents->value.get() + contents->offset);
}
throw UnsupportedOperationException(__FILE__, __LINE__, "Not yet implemented for offset values");
@@ -527,8 +551,7 @@ String String::concat(const std::string& string) const {
buffer.value.get(), 0, contents->length);
}
- System::arraycopy((const unsigned char*) string.c_str(),
- 0, buffer.value.get(), contents->length, string.length());
+ System::arraycopy(string.c_str(), 0, buffer.value.get(), contents->length, string.length());
return String(&buffer);
}
@@ -553,8 +576,7 @@ String String::concat(const char* string) const {
buffer.value.get(), 0, contents->length);
}
- System::arraycopy((const unsigned char*) string, 0,
- buffer.value.get(), contents->length, length);
+ System::arraycopy(string, 0, buffer.value.get(), contents->length, length);
return String(&buffer);
}
@@ -667,7 +689,7 @@ bool String::equalsIgnoreCase(const String& string) const {
int end = contents->offset + contents->length;
char c1, c2;
- ArrayPointer<unsigned char> target = string.contents->value;
+ ArrayPointer<char> target = string.contents->value;
while (offsetThis < end) {
if ((c1 = contents->value[offsetThis++]) != (c2 = target[offsetOther++])) {
@@ -804,7 +826,7 @@ int String::indexOf(const String& subString, int start) const {
return -1;
}
- unsigned char* target = subString.contents->value.get();
+ char* target = subString.contents->value.get();
int subOffset = subString.contents->offset;
char firstChar = target[subOffset];
@@ -961,7 +983,7 @@ int String::lastIndexOf(const String& subString, int start) const {
}
// count and subCount are both >= 1
- unsigned char* target = subString.contents->value.get();
+ char* target = subString.contents->value.get();
int subOffset = subString.contents->offset;
char firstChar = target[subOffset];
int end = subOffset + subCount;
@@ -1267,10 +1289,14 @@ String String::toUpperCase() const {
////////////////////////////////////////////////////////////////////////////////
std::string String::toString() const {
- if (this->contents->value == NULL) {
+ if (this->contents == NULL) {
return "null";
}
+ if (this->contents->length == 0) {
+ return "";
+ }
+
return std::string((const char*) contents->value.get() + contents->offset, this->length());
}
@@ -1344,7 +1370,7 @@ namespace lang {
std::ostream& operator<<(std::ostream &out, const String& target) {
if (target.isEmpty()) {
- out << "NULL";
+ out << "";
}
for (int i = 0; i < target.length(); ++i) {
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/main/decaf/lang/String.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/lang/String.h b/activemq-cpp/src/main/decaf/lang/String.h
index 30d2caf..8865dd8 100644
--- a/activemq-cpp/src/main/decaf/lang/String.h
+++ b/activemq-cpp/src/main/decaf/lang/String.h
@@ -44,11 +44,26 @@ namespace lang {
public:
/**
- * Creates a new empty String object.
+ * Creates a new empty String object. This value is equivalent to
+ * calling String("") and all methods will behave as if the string is
+ * an empty string.
*/
String();
/**
+ * Create a new String instance that contains N copies of the given character
+ * value.
+ *
+ * @param value
+ * The character to fill this String with.
+ * @param count
+ * The number of copies of the character to fill.
+ *
+ * @throws IndexOutOfBoundsException if the count parameter is negative.
+ */
+ String(const char value, int count);
+
+ /**
* Create a new String object that represents the given STL string
*
* @param source
@@ -223,15 +238,11 @@ namespace lang {
String operator+ (const std::string& other) const;
String operator+ (const char* other) const;
- private:
-
- // TODO - String is not always NULL terminated at the moment.
-
/**
* Returns a const char* value to allow easier coexistence with standard c++
- * string operations. The value returned will be NULL if the String is empty.
+ * string operations..
*
- * @returns a const char* value for this String or NULL if empty.
+ * @returns a const char* value for this String.
*/
const char* c_str() const;
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/main/decaf/net/URL.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/net/URL.cpp b/activemq-cpp/src/main/decaf/net/URL.cpp
index 990e767..9094c07 100644
--- a/activemq-cpp/src/main/decaf/net/URL.cpp
+++ b/activemq-cpp/src/main/decaf/net/URL.cpp
@@ -27,6 +27,7 @@
#include <decaf/net/MalformedURLException.h>
#include <decaf/lang/exceptions/IllegalArgumentException.h>
#include <decaf/internal/net/URLType.h>
+#include <decaf/internal/net/URLUtils.h>
#include <decaf/util/HashMap.h>
#include <decaf/util/concurrent/Mutex.h>
@@ -138,6 +139,7 @@ URL::URL(const String& protocol, const String& host, int port, const String& fil
////////////////////////////////////////////////////////////////////////////////
void URL::initialize(const URL* context, const String& theSpec, URLStreamHandler* handler) {
+
if (handler != NULL) {
impl->streamHandler.reset(handler);
}
@@ -160,15 +162,18 @@ void URL::initialize(const URL* context, const String& theSpec, URLStreamHandler
// According to RFC 2396 scheme part should match the following expression:
// alpha *( alpha | digit | "+" | "-" | "." )
char c = protocol.charAt(0);
- bool valid = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
- for (int i = 1; valid && (i < protocol.length()); i++) {
+ bool valid = true;
+// bool valid = ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
+// for (int i = 1; valid && (i < protocol.length()); i++) {
+ for (int i = 0; valid && (i < protocol.length()); i++) {
c = protocol.charAt(i);
- valid = ('a' <= c && c <= 'z') ||
- ('A' <= c && c <= 'Z') ||
- ('0' <= c && c <= '9') ||
- (c == '+') ||
- (c == '-') ||
- (c == '.');
+ valid = URLUtils::isValidSchemeChar(i, c);
+// valid = ('a' <= c && c <= 'z') ||
+// ('A' <= c && c <= 'Z') ||
+// ('0' <= c && c <= '9') ||
+// (c == '+') ||
+// (c == '-') ||
+// (c == '.');
}
if (!valid) {
impl->url.setProtocol(String());
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/main/decaf/net/URLStreamHandler.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/net/URLStreamHandler.cpp b/activemq-cpp/src/main/decaf/net/URLStreamHandler.cpp
index 45dcd90..d4d9b0c 100644
--- a/activemq-cpp/src/main/decaf/net/URLStreamHandler.cpp
+++ b/activemq-cpp/src/main/decaf/net/URLStreamHandler.cpp
@@ -24,6 +24,7 @@
#include <decaf/internal/util/StringUtils.h>
#include <decaf/net/UnknownHostException.h>
#include <decaf/lang/Integer.h>
+#include <decaf/internal/net/URLUtils.h>
using namespace decaf;
using namespace decaf::net;
@@ -31,60 +32,28 @@ using namespace decaf::lang;
using namespace decaf::lang::exceptions;
using namespace decaf::internal;
using namespace decaf::internal::util;
+using namespace decaf::internal::net;
////////////////////////////////////////////////////////////////////////////////
-namespace {
-
- /**
- * File based URL instance with an empty host value are always considered
- * to have a host value of "localhost".
- */
- String getHost(const URL& url) {
- String host = url.getHost();
- if (url.getProtocol().equals("file") && host.isEmpty()) {
- return "localhost";
- }
- return host;
- }
-
- /**
- * Canonicalize the path, i.e. remove ".." and "." occurrences.
- *
- * @param path the path to be canonicalized
- *
- * @return the canonicalized path
- */
- String canonicalizePath(const String& original) {
- String path = original;
- int dirIndex;
-
- while ((dirIndex = path.indexOf("/./")) >= 0) {
- path = path.substring(0, dirIndex + 1) + path.substring(dirIndex + 3);
- }
+URLStreamHandler::~URLStreamHandler() {}
- if (path.endsWith("/.")) {
- path = path.substring(0, path.length() - 1);
- }
+////////////////////////////////////////////////////////////////////////////////
+namespace {
- while ((dirIndex = path.indexOf("/../")) >= 0) {
- if (dirIndex != 0) {
- path = path.substring(0, path.lastIndexOf('/', dirIndex - 1)) + path.substring(dirIndex + 3);
- } else {
- path = path.substring(dirIndex + 3);
- }
- }
+ String relativePath(const String& base, const String& path) {
- if (path.endsWith("/..") && path.length() > 3) {
- path = path.substring(0, path.lastIndexOf('/', path.length() - 4) + 1);
+ if (path.startsWith("/")) {
+ return URLUtils::canonicalizePath(path, true);
+ } else if (base != "") {
+ String combined = base.substring(0, base.lastIndexOf('/') + 1) + path;
+ return URLUtils::canonicalizePath(combined, true);
+ } else {
+ return path;
}
- return path;
}
}
////////////////////////////////////////////////////////////////////////////////
-URLStreamHandler::~URLStreamHandler() {}
-
-////////////////////////////////////////////////////////////////////////////////
URLConnection* URLStreamHandler::openConnection(const URL& url DECAF_UNUSED, const Proxy* proxy DECAF_UNUSED) {
throw UnsupportedOperationException(__FILE__, __LINE__, "method has not been implemented yet");
}
@@ -157,8 +126,8 @@ bool URLStreamHandler::hostsEqual(const URL& source, const URL& other) const {
// }
// Compare by name.
- String host1 = getHost(source);
- String host2 = getHost(other);
+ String host1 = URLUtils::getHost(source);
+ String host2 = URLUtils::getHost(other);
if (host1.isEmpty() && host2.isEmpty()) {
return true;
}
@@ -216,13 +185,12 @@ int URLStreamHandler::getDefaultPort() const {
void URLStreamHandler::parseURL(URL& url, const String& spec, int start, int limit) {
if (limit < start || limit < 0) {
- if (((limit <= Integer::MIN_VALUE + 1) && (start >= spec.length() || start < 0)) ||
+ if ((limit <= Integer::MIN_VALUE + 1 && (start >= spec.length() || start < 0)) ||
(spec.startsWith("//", start) && spec.indexOf('/', start + 2) == -1)) {
-
throw StringIndexOutOfBoundsException(__FILE__, __LINE__, limit);
}
if (this != url.getURLStreamHandler()) {
- throw new SecurityException();
+ throw SecurityException(__FILE__, __LINE__, "Only the URL's stream handler can modify");
}
return;
}
@@ -230,7 +198,6 @@ void URLStreamHandler::parseURL(URL& url, const String& spec, int start, int lim
String parseString = spec.substring(start, limit);
limit -= start;
int fileIdx = 0;
- bool fileIsRelative = false;
// Default is to use info from context
String host = url.getHost();
@@ -258,7 +225,6 @@ void URLStreamHandler::parseURL(URL& url, const String& spec, int start, int lim
fileIdx = limit;
// Use default
file = "";
- fileIsRelative = true;
}
int hostEnd = fileIdx;
if (refIdx != -1 && refIdx < fileIdx) {
@@ -272,9 +238,10 @@ void URLStreamHandler::parseURL(URL& url, const String& spec, int start, int lim
}
portIdx = parseString.indexOf(':', userIdx == -1 ? hostIdx : userIdx);
- int endOfIPv6Addr = parseString.indexOf(']');
+ // TODO could add this to string and return -1
+ int endOfIPv6Addr = URLUtils::findFirstOf(parseString, "]", hostIdx, fileIdx);
// if there are square braces, ie. IPv6 address, use last ':'
- if (endOfIPv6Addr != -1) {
+ if (endOfIPv6Addr != fileIdx) {
try {
if (parseString.length() > endOfIPv6Addr + 1) {
char c = parseString.charAt(endOfIPv6Addr + 1);
@@ -307,6 +274,7 @@ void URLStreamHandler::parseURL(URL& url, const String& spec, int start, int lim
if (refIdx > -1) {
ref = parseString.substring(refIdx + 1, limit);
}
+
int fileEnd = (refIdx == -1 ? limit : refIdx);
int queryIdx = parseString.lastIndexOf('?', fileEnd);
@@ -332,7 +300,7 @@ void URLStreamHandler::parseURL(URL& url, const String& spec, int start, int lim
if (fileIdx < limit && parseString.charAt(fileIdx) == '/') {
file = parseString.substring(fileIdx, fileEnd);
} else if (fileEnd > fileIdx) {
- if (file.equals("") && fileIsRelative) {
+ if (file.equals("") && !host.equals("")) {
file = "/";
} else if (file.startsWith("/")) {
canonicalize = true;
@@ -341,15 +309,14 @@ void URLStreamHandler::parseURL(URL& url, const String& spec, int start, int lim
if (last == 0) {
file = parseString.substring(fileIdx, fileEnd);
} else {
- file = file.substring(0, last)
- + parseString.substring(fileIdx, fileEnd);
+ file = file.substring(0, last) + parseString.substring(fileIdx, fileEnd);
}
}
}
if (canonicalize) {
// modify file if there's any relative referencing
- file = canonicalizePath(file);
+ file = URLUtils::canonicalizePath(file, false);
}
setURL(url, url.getProtocol(), host, port, authority, userInfo, file, query, ref);
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/test/decaf/lang/StringTest.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/test/decaf/lang/StringTest.cpp b/activemq-cpp/src/test/decaf/lang/StringTest.cpp
index ef00bb6..28e35c1 100644
--- a/activemq-cpp/src/test/decaf/lang/StringTest.cpp
+++ b/activemq-cpp/src/test/decaf/lang/StringTest.cpp
@@ -36,7 +36,7 @@ StringTest::~StringTest() {
}
////////////////////////////////////////////////////////////////////////////////
-void StringTest::testDEfaultConstructor() {
+void StringTest::testDefaultConstructor() {
String test;
CPPUNIT_ASSERT_MESSAGE("Default string should equal empty", test == "");
@@ -68,6 +68,126 @@ void StringTest::testConstructorStdString() {
}
////////////////////////////////////////////////////////////////////////////////
+void StringTest::testConstructorCString() {
+
+ const char* cstring("ABCDE");
+
+ String test(cstring);
+
+ CPPUNIT_ASSERT(test.length() == 5);
+ CPPUNIT_ASSERT(test.isEmpty() == false);
+
+ CPPUNIT_ASSERT_MESSAGE("String and C string should be equal", test == cstring);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ test.charAt(5),
+ IndexOutOfBoundsException);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void StringTest::testConstructorCStringWithSize() {
+
+ const char* cstring("ABCDEF");
+ const char* expected("ABCDE");
+
+ String test(cstring, 5);
+
+ CPPUNIT_ASSERT(test.length() == 5);
+ CPPUNIT_ASSERT(test.isEmpty() == false);
+
+ CPPUNIT_ASSERT_MESSAGE("String and C string should be equal", test == expected);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ test.charAt(5),
+ IndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an NullPointerException",
+ String((const char*)NULL, 10),
+ NullPointerException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ String(cstring, -1),
+ IndexOutOfBoundsException);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void StringTest::testConstructorCStringOffsetAndLength() {
+
+ const char* cstring("1ABCDEF");
+ const char* expected("ABCDE");
+
+ String test(cstring, 1, 5);
+
+ CPPUNIT_ASSERT(test.length() == 5);
+ CPPUNIT_ASSERT(test.isEmpty() == false);
+
+ CPPUNIT_ASSERT_MESSAGE("String and C string should be equal", test == expected);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ test.charAt(5),
+ IndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an NullPointerException",
+ String((const char*)NULL, 1, 20),
+ NullPointerException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ String(cstring, -1, 5),
+ IndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ String(cstring, 1, -5),
+ IndexOutOfBoundsException);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void StringTest::testConstructorCStringSizeOffsetAndLength() {
+
+ const char* cstring("1ABCDEF");
+ const char* expected("ABCDE");
+
+ String test(cstring, 7, 1, 5);
+
+ CPPUNIT_ASSERT(test.length() == 5);
+ CPPUNIT_ASSERT(test.isEmpty() == false);
+
+ CPPUNIT_ASSERT_MESSAGE("String and C string should be equal", test == expected);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ test.charAt(5),
+ IndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an NullPointerException",
+ String((const char*)NULL, 7, 1, 4),
+ NullPointerException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ String(cstring, -1, 0, 5),
+ IndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ String(cstring, 7, -1, 5),
+ IndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an IndexOutOfBoundsException",
+ String(cstring, 7, 1, -5),
+ IndexOutOfBoundsException);
+}
+
+////////////////////////////////////////////////////////////////////////////////
void StringTest::testConstructorString() {
String original("ABCDE");
@@ -102,6 +222,10 @@ void StringTest::testAssignmentString() {
CPPUNIT_ASSERT_EQUAL_MESSAGE("String assignment failed", input, String("HelloWorld"));
transient = world;
CPPUNIT_ASSERT_EQUAL_MESSAGE("String assignment failed", transient, world);
+
+ String toEmpty("ABCDEF");
+ toEmpty = String("");
+ CPPUNIT_ASSERT_MESSAGE("String did not get set to empty", toEmpty.isEmpty());
}
////////////////////////////////////////////////////////////////////////////////
@@ -121,6 +245,10 @@ void StringTest::testAssignmentStdString() {
CPPUNIT_ASSERT_EQUAL_MESSAGE("String assignment failed", input, String("HelloWorld"));
transient = world;
CPPUNIT_ASSERT_MESSAGE("String assignment failed", transient.equals(world));
+
+ String toEmpty("ABCDEF");
+ toEmpty = std::string("");
+ CPPUNIT_ASSERT_MESSAGE("String did not get set to empty", toEmpty.isEmpty());
}
////////////////////////////////////////////////////////////////////////////////
@@ -140,6 +268,10 @@ void StringTest::testAssignmentCString() {
CPPUNIT_ASSERT_EQUAL_MESSAGE("String assignment failed", input, String("HelloWorld"));
transient = world;
CPPUNIT_ASSERT_MESSAGE("String assignment failed", transient.equals(world));
+
+ String toEmpty("ABCDEF");
+ toEmpty = "";
+ CPPUNIT_ASSERT_MESSAGE("String did not get set to empty", toEmpty.isEmpty());
}
////////////////////////////////////////////////////////////////////////////////
@@ -283,6 +415,27 @@ void StringTest::testToCharArray() {
}
////////////////////////////////////////////////////////////////////////////////
+void StringTest::testCStr() {
+
+ String input("ABCDE");
+ const char* result = input.c_str();
+
+ for (int i = 0; i < input.length(); i++) {
+ CPPUNIT_ASSERT_MESSAGE("Returned incorrect char aray", input.charAt(i) == result[i]);
+ }
+
+ std::string empty("");
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid string returned", empty, std::string(String().c_str()));
+
+ const String hw("HelloWorld");
+ String substr = hw.substring(5);
+ String world = "World";
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid string returned", world, substr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
void StringTest::testEndsWith() {
const String input("HelloWorld");
@@ -496,6 +649,8 @@ void StringTest::testToLowerCase() {
String lower = "helloworld";
String upper = "HELLOWORLD";
+ upper.toLowerCase();
+
CPPUNIT_ASSERT_MESSAGE("toLowerCase case conversion did not succeed",
upper.toLowerCase().equals(lower));
CPPUNIT_ASSERT_MESSAGE("toLowerCase case non-conversion did not succeed",
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/test/decaf/lang/StringTest.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/test/decaf/lang/StringTest.h b/activemq-cpp/src/test/decaf/lang/StringTest.h
index 98cc294..c2dd2ed 100644
--- a/activemq-cpp/src/test/decaf/lang/StringTest.h
+++ b/activemq-cpp/src/test/decaf/lang/StringTest.h
@@ -27,7 +27,11 @@ namespace lang {
class StringTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE( StringTest );
- CPPUNIT_TEST( testDEfaultConstructor );
+ CPPUNIT_TEST( testDefaultConstructor );
+ CPPUNIT_TEST( testConstructorCString );
+ CPPUNIT_TEST( testConstructorCStringWithSize );
+ CPPUNIT_TEST( testConstructorCStringOffsetAndLength );
+ CPPUNIT_TEST( testConstructorCStringSizeOffsetAndLength );
CPPUNIT_TEST( testConstructorStdString );
CPPUNIT_TEST( testConstructorString );
CPPUNIT_TEST( testAssignmentString );
@@ -40,6 +44,7 @@ namespace lang {
CPPUNIT_TEST( testTrim );
CPPUNIT_TEST( testToString );
CPPUNIT_TEST( testToCharArray );
+ CPPUNIT_TEST( testCStr );
CPPUNIT_TEST( testRegionMatches );
CPPUNIT_TEST( testRegionMatchesCaseSensitive );
CPPUNIT_TEST( testStartsWith );
@@ -96,7 +101,11 @@ namespace lang {
StringTest();
virtual ~StringTest();
- void testDEfaultConstructor();
+ void testDefaultConstructor();
+ void testConstructorCString();
+ void testConstructorCStringWithSize();
+ void testConstructorCStringOffsetAndLength();
+ void testConstructorCStringSizeOffsetAndLength();
void testConstructorStdString();
void testConstructorString();
void testAssignmentString();
@@ -109,6 +118,7 @@ namespace lang {
void testTrim();
void testToString();
void testToCharArray();
+ void testCStr();
void testRegionMatches();
void testRegionMatchesCaseSensitive();
void testStartsWith();
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/test/decaf/net/URLTest.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/test/decaf/net/URLTest.cpp b/activemq-cpp/src/test/decaf/net/URLTest.cpp
index 15b53c4..e95f23e 100644
--- a/activemq-cpp/src/test/decaf/net/URLTest.cpp
+++ b/activemq-cpp/src/test/decaf/net/URLTest.cpp
@@ -21,6 +21,10 @@
#include <decaf/net/URL.h>
#include <decaf/lang/Integer.h>
#include <decaf/lang/Boolean.h>
+#include <decaf/net/URLStreamHandler.h>
+#include <decaf/net/URLStreamHandlerFactory.h>
+#include <decaf/lang/exceptions/SecurityException.h>
+#include <decaf/lang/exceptions/StringIndexOutOfBoundsException.h>
using namespace std;
using namespace decaf;
@@ -29,6 +33,33 @@ using namespace decaf::lang;
using namespace decaf::lang::exceptions;
////////////////////////////////////////////////////////////////////////////////
+namespace {
+
+ class MyURLStreamHandler : public URLStreamHandler {
+ protected:
+
+ virtual URLConnection* openConnection(const URL& url) {
+ return NULL;
+ }
+
+ public:
+
+ void parse(URL& url, const String& spec, int start, int end) {
+ parseURL(url, spec, start, end);
+ }
+ };
+
+ class MyURLStreamHandlerFactory : public URLStreamHandlerFactory {
+ public:
+
+ virtual URLStreamHandler* createURLStreamHandler(const std::string& protocol) {
+ return new MyURLStreamHandler();
+ }
+ };
+
+}
+
+////////////////////////////////////////////////////////////////////////////////
URLTest::URLTest() {
}
@@ -67,11 +98,11 @@ void URLTest::testConstructor1() {
// test for no port
URL d("file://www.yahoo3.com/dir1/dir2/test.cgi#anchor1");
- CPPUNIT_ASSERT_EQUAL_MESSAGE("u2a returns a wrong protocol", String("file"), d.getProtocol());
- CPPUNIT_ASSERT_EQUAL_MESSAGE("u2a returns a wrong host", String("www.yahoo3.com"), d.getHost());
- CPPUNIT_ASSERT_EQUAL_MESSAGE("u2a returns a wrong port", -1, d.getPort());
- CPPUNIT_ASSERT_EQUAL_MESSAGE("u2a returns a wrong file", String("/dir1/dir2/test.cgi"), d.getFile());
- CPPUNIT_ASSERT_EQUAL_MESSAGE("u2a returns a wrong anchor", String("anchor1"), d.getRef());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("d returns a wrong protocol", String("file"), d.getProtocol());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("d returns a wrong host", String("www.yahoo3.com"), d.getHost());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("d returns a wrong port", -1, d.getPort());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("d returns a wrong file", String("/dir1/dir2/test.cgi"), d.getFile());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("d returns a wrong anchor", String("anchor1"), d.getRef());
// test for no file, no port
URL e("http://www.yahoo4.com/");
@@ -237,6 +268,53 @@ void URLTest::testConstructor3() {
}
////////////////////////////////////////////////////////////////////////////////
+void URLTest::testConstructor4() {
+
+ URL context("http://www.yahoo.com");
+
+ // basic ones
+ URL a(context, "file.java", new MyURLStreamHandler);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("1 returns a wrong protocol", String("http"), a.getProtocol());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("1 returns a wrong host", String("www.yahoo.com"), a.getHost());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("1 returns a wrong port", -1, a.getPort());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("1 returns a wrong file", String("/file.java"), a.getFile());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("1 returns a wrong anchor", String(), a.getRef());
+
+ URL b(context, "systemresource:/+/FILE0/test.java", new MyURLStreamHandler);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("2 returns a wrong protocol", String("systemresource"), b.getProtocol());
+ CPPUNIT_ASSERT_MESSAGE("2 returns a wrong host", b.getHost().equals(""));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("2 returns a wrong port", -1, b.getPort());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("2 returns a wrong file", String("/+/FILE0/test.java"), b.getFile());
+ CPPUNIT_ASSERT_MESSAGE("2 returns a wrong anchor", b.getRef().equals(""));
+
+ URL c(context, "dir1/dir2/../file.java", NULL);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("3 returns a wrong protocol", String("http"), c.getProtocol());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("3 returns a wrong host", String("www.yahoo.com"), c.getHost());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("3 returns a wrong port", -1, c.getPort());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("3 returns a wrong file", String("/dir1/dir2/../file.java"), c.getFile());
+ CPPUNIT_ASSERT_MESSAGE("3 returns a wrong anchor", c.getRef().equals(""));
+
+ // test for question mark processing
+ URL d("http://www.foo.com/d0/d1/d2/cgi-bin?foo=bar/baz");
+
+ // test for relative file and out of bound "/../" processing
+ URL e(d, "../dir1/dir2/../file.java", new MyURLStreamHandler);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("A) returns a wrong file: ", String("/d0/d1/dir1/file.java"), e.getFile());
+
+ // test for absolute and relative file processing
+ URL f(d, "/../dir1/dir2/../file.java", NULL);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("B) returns a wrong file", String("/../dir1/dir2/../file.java"), f.getFile());
+
+ CPPUNIT_ASSERT_NO_THROW(URL("http://www.ibm.com"));
+
+ URL test("http://www.ibm.com");
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an MalformedURLException",
+ URL(test, String()),
+ MalformedURLException);
+}
+
+////////////////////////////////////////////////////////////////////////////////
void URLTest::testEquals() {
URL u("http://www.apache.org:8080/dir::23??????????test.html");
@@ -289,3 +367,221 @@ void URLTest::testSameFile() {
// URL l("ftp://localhost/anyfile");
// CPPUNIT_ASSERT(!k.sameFile(l));
}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testToString() {
+
+ URL a("http://www.yahoo2.com:9999");
+ URL b("http://www.yahoo1.com:8080/dir1/dir2/test.cgi?point1.html#anchor1");
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("a) Does not return the right url string",
+ std::string("http://www.yahoo1.com:8080/dir1/dir2/test.cgi?point1.html#anchor1"), b.toString());
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("b) Does not return the right url string",
+ std::string("http://www.yahoo2.com:9999"), a.toString());
+
+ CPPUNIT_ASSERT_MESSAGE("c) Does not return the right url string",
+ a.equals(URL(a.toString())));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testToExternalForm() {
+ URL b("http://www.yahoo2.com:9999");
+ URL a("http://www.yahoo1.com:8080/dir1/dir2/test.cgi?point1.html#anchor1");
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("a) Does not return the right url string",
+ String("http://www.yahoo1.com:8080/dir1/dir2/test.cgi?point1.html#anchor1"), a.toExternalForm());
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("b) Does not return the right url string",
+ String("http://www.yahoo2.com:9999"), b.toExternalForm());
+
+ CPPUNIT_ASSERT_MESSAGE("c) Does not return the right url string",
+ a.equals(URL(a.toExternalForm())));
+
+ URL c("http:index");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("2 wrong external form", String("http:index"), c.toExternalForm());
+
+ URL d("http", "", "index");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("2 wrong external form", String("http:index"), d.toExternalForm());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testGetFile() {
+
+ URL a("http", "www.yahoo.com:8080", 1233, "test/!@$%^&*/test.html#foo");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("returns a wrong file", String("test/!@$%^&*/test.html"), a.getFile());
+ URL b("http", "www.yahoo.com:8080", 1233, "");
+ CPPUNIT_ASSERT_MESSAGE("returns a wrong file", b.getFile().equals(""));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testGetHost() {
+
+ String ipv6Host = "FEDC:BA98:7654:3210:FEDC:BA98:7654:3210";
+ URL url("http", ipv6Host, -1, "myfile");
+ CPPUNIT_ASSERT_EQUAL((String("[") + ipv6Host + "]"), url.getHost());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testGetPort() {
+ URL a("http://member12.c++.com:9999");
+ CPPUNIT_ASSERT_MESSAGE("return wrong port number", a.getPort() == 9999);
+ URL b("http://member12.c++.com:9999/");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("return wrong port number", 9999, b.getPort());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testGetDefaultPort() {
+ URL a("http://member12.c++.com:9999");
+ CPPUNIT_ASSERT_EQUAL(80, a.getDefaultPort());
+
+ URL b("http://www.google.com:80/example?language[id]=2");
+ CPPUNIT_ASSERT_EQUAL(String("www.google.com"), b.getHost());
+ CPPUNIT_ASSERT_EQUAL(80, b.getPort());
+
+ // TODO
+// URL b("ftp://member12.c++.com:9999/");
+// CPPUNIT_ASSERT_EQUAL(21, b.getDefaultPort());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testGetProtocol() {
+ URL a("http://www.yahoo2.com:9999");
+ CPPUNIT_ASSERT_MESSAGE("u returns a wrong protocol: ", a.getProtocol().equals("http"));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testGetRef() {
+ URL b("http://www.yahoo2.com:9999");
+ URL a("http://www.yahoo1.com:8080/dir1/dir2/test.cgi?point1.html#anchor1");
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("returns a wrong anchor1", String("anchor1"), a.getRef());
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("returns a wrong anchor2", String(), b.getRef() );
+ URL c("http://www.yahoo2.com#ref");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("returns a wrong anchor3", String("ref"), c.getRef());
+ URL d("http://www.yahoo2.com/file#ref1#ref2");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("returns a wrong anchor4", String("ref1#ref2"), d.getRef());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testGetAuthority() {
+
+ URL a("http", "hostname", 80, "/java?q1#ref");
+ CPPUNIT_ASSERT_EQUAL(String("hostname:80"), a.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(String("hostname"), a.getHost());
+ CPPUNIT_ASSERT_EQUAL(String(), a.getUserInfo());
+ CPPUNIT_ASSERT_EQUAL(String("/java?q1"), a.getFile());
+ CPPUNIT_ASSERT_EQUAL(String("/java"), a.getPath());
+ CPPUNIT_ASSERT_EQUAL(String("q1"), a.getQuery());
+ CPPUNIT_ASSERT_EQUAL(String("ref"), a.getRef());
+
+ URL b("http", "u:p@home", 80, "/java?q1#ref");
+ CPPUNIT_ASSERT_EQUAL(String("[u:p@home]:80"), b.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(String("[u:p@home]"), b.getHost());
+ CPPUNIT_ASSERT_EQUAL(String(""), b.getUserInfo());
+ CPPUNIT_ASSERT_EQUAL(String("/java?q1"), b.getFile());
+ CPPUNIT_ASSERT_EQUAL(String("/java"), b.getPath());
+ CPPUNIT_ASSERT_EQUAL(String("q1"), b.getQuery());
+ CPPUNIT_ASSERT_EQUAL(String("ref"), b.getRef());
+
+ URL c("http", "home", -1, "/java");
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong authority2", String("home"), c.getAuthority());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong userInfo2", String(), c.getUserInfo());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong host2", String("home"), c.getHost());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong file2", String("/java"), c.getFile());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong path2", String("/java"), c.getPath());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong query2", String(), c.getQuery());
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong ref2", String(), c.getRef());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testToURI() {
+ URL a("http://www.apache.org");
+ URI uri = a.toURI();
+ CPPUNIT_ASSERT(a.equals(uri.toURL()));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testURLStreamHandlerParseURL() {
+
+ URL url("http://localhost");
+ MyURLStreamHandler handler;
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "//", 0, Integer::MIN_VALUE),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "1234//", 4, Integer::MIN_VALUE),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "1", -1, 0),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an SecurityException",
+ handler.parse(url, "1", 3, 2),
+ SecurityException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an SecurityException",
+ handler.parse(url, "11", 1, Integer::MIN_VALUE),
+ SecurityException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "any", 10, Integer::MIN_VALUE),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "any", 10, Integer::MIN_VALUE+1),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "any", Integer::MIN_VALUE, Integer::MIN_VALUE),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "any", Integer::MIN_VALUE, 2),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an StringIndexOutOfBoundsException",
+ handler.parse(url, "any", -1, 2),
+ StringIndexOutOfBoundsException);
+
+ CPPUNIT_ASSERT_THROW_MESSAGE(
+ "Should have thrown an SecurityException",
+ handler.parse(url, "any", -1, -1),
+ SecurityException);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testUrlParts() {
+ URL url("http://username:password@host:8080/directory/file?query#ref");
+ CPPUNIT_ASSERT_EQUAL(String("http"), url.getProtocol());
+ CPPUNIT_ASSERT_EQUAL(String("username:password@host:8080"), url.getAuthority());
+ CPPUNIT_ASSERT_EQUAL(String("username:password"), url.getUserInfo());
+ CPPUNIT_ASSERT_EQUAL(String("host"), url.getHost());
+ CPPUNIT_ASSERT_EQUAL(8080, url.getPort());
+ CPPUNIT_ASSERT_EQUAL(80, url.getDefaultPort());
+ CPPUNIT_ASSERT_EQUAL(String("/directory/file?query"), url.getFile());
+ CPPUNIT_ASSERT_EQUAL(String("/directory/file"), url.getPath());
+ CPPUNIT_ASSERT_EQUAL(String("query"), url.getQuery());
+ CPPUNIT_ASSERT_EQUAL(String("ref"), url.getRef());
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void URLTest::testFileEqualsWithEmptyHost() {
+ URL a("file", "", -1, "/a/");
+ URL b("file:/a/");
+ CPPUNIT_ASSERT(a.equals(b));
+}
http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/8db1d9ae/activemq-cpp/src/test/decaf/net/URLTest.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/test/decaf/net/URLTest.h b/activemq-cpp/src/test/decaf/net/URLTest.h
index f203b2b..0d74156 100644
--- a/activemq-cpp/src/test/decaf/net/URLTest.h
+++ b/activemq-cpp/src/test/decaf/net/URLTest.h
@@ -30,8 +30,22 @@ namespace net {
CPPUNIT_TEST( testConstructor1 );
CPPUNIT_TEST( testConstructor2 );
CPPUNIT_TEST( testConstructor3 );
+ CPPUNIT_TEST( testConstructor4 );
CPPUNIT_TEST( testEquals );
CPPUNIT_TEST( testSameFile );
+ CPPUNIT_TEST( testToString );
+ CPPUNIT_TEST( testToExternalForm );
+ CPPUNIT_TEST( testGetFile );
+ CPPUNIT_TEST( testGetHost );
+ CPPUNIT_TEST( testGetPort );
+ CPPUNIT_TEST( testGetDefaultPort );
+ CPPUNIT_TEST( testGetProtocol );
+ CPPUNIT_TEST( testGetRef );
+ CPPUNIT_TEST( testGetAuthority );
+ CPPUNIT_TEST( testToURI );
+ CPPUNIT_TEST( testURLStreamHandlerParseURL );
+ CPPUNIT_TEST( testUrlParts );
+ CPPUNIT_TEST( testFileEqualsWithEmptyHost );
CPPUNIT_TEST_SUITE_END();
public:
@@ -42,8 +56,22 @@ namespace net {
void testConstructor1();
void testConstructor2();
void testConstructor3();
+ void testConstructor4();
void testEquals();
void testSameFile();
+ void testToString();
+ void testToExternalForm();
+ void testGetFile();
+ void testGetHost();
+ void testGetPort();
+ void testGetDefaultPort();
+ void testGetProtocol();
+ void testGetRef();
+ void testGetAuthority();
+ void testToURI();
+ void testURLStreamHandlerParseURL();
+ void testUrlParts();
+ void testFileEqualsWithEmptyHost();
};