lib/onebox/helpers.rb in onebox-1.8.87 vs lib/onebox/helpers.rb in onebox-1.8.88
- old
+ new
@@ -183,7 +183,54 @@
"#{uri.scheme}://#{uri.host.sub(/\/$/, '')}/#{src.sub(/^\//, '')}"
end
end
src
end
+
+ RFC_3986_URI_REGEX = /^(?<scheme>([^:\/?#]+):)?(?<authority>\/\/([^\/?#]*))?(?<path>[^?#]*)(\?(?<query>[^#]*))?(#(?<fragment>.*))?$/
+
+ # Percent-encodes a URI query parameter per RFC3986 - https://tools.ietf.org/html/rfc3986
+ def self.uri_query_encode(query_string)
+ return "" unless query_string
+
+ # query can encode space to %20 OR +
+ # + MUST be encoded as %2B
+ # in RFC3968 both query and fragment are defined as:
+ # = *( pchar / "/" / "?" )
+ # CGI.escape turns space into + which is the most backward compatible
+ # however it doesn't roundtrip through URI.unescape which prefers %20
+ CGI.escape(query_string).gsub('+', '%20')
+ end
+
+ # Percent-encodes a URI string per RFC3986 - https://tools.ietf.org/html/rfc3986
+ def self.uri_encode(url)
+ return "" unless url
+
+ # parse uri into named matches, then reassemble properly encoded
+ parts = url.match(RFC_3986_URI_REGEX)
+
+ encoded = ""
+ encoded += parts[:scheme] unless parts[:scheme].nil?
+ encoded += parts[:authority] unless parts[:authority].nil?
+
+ # path requires space to be encoded as %20 (NEVER +)
+ # + should be left unencoded
+ # URI::parse and URI::Generic.build don't like paths encoded with CGI.escape
+ # URI.escape does not change / to %2F and : to %3A like CGI.escape
+ encoded += URI.escape(parts[:path]) unless parts[:path].nil?
+
+ # each query parameter
+ if !parts[:query].nil?
+ query_string = parts[:query].split('&').map do |pair|
+ # can optionally be separated by an =
+ pair.split('=').map do |v|
+ uri_query_encode(v)
+ end.join('=')
+ end.join('&')
+ encoded += '?' + query_string
+ end
+
+ encoded += '#' + uri_query_encode(parts[:fragment]) unless parts[:fragment].nil?
+ encoded
+ end
end
end