Permalink
Browse files

More complete URL handling and tests.

  • Loading branch information...
1 parent a19bec7 commit 8db1d9ae25a6df071ab6747c461357f0b3c1e67b @tabish121 tabish121 committed Nov 5, 2013
@@ -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 \
@@ -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;
+}
@@ -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_ */
Oops, something went wrong.

0 comments on commit 8db1d9a

Please sign in to comment.