Skip to content

Commit

Permalink
Implement escapeURIComponent for JRuby
Browse files Browse the repository at this point in the history
  • Loading branch information
byroot committed Nov 7, 2023
1 parent a60754b commit c90c9ea
Showing 1 changed file with 48 additions and 7 deletions.
55 changes: 48 additions & 7 deletions ext/java/org/jruby/ext/cgi/escape/CGIEscape.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ static boolean ISXDIGIT(byte[] cstrBytes, int i) {
return (cstrByte >= '0' && cstrByte <= '9') || (cstrByte >= 'a' && cstrByte <= 'f') || (cstrByte >= 'A' && cstrByte <= 'F');
}

static boolean url_unreserved_char(int c) {
static boolean url_unreserved_char(int c, boolean escapePlus) {
switch (c) {
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j':
Expand All @@ -255,6 +255,8 @@ static boolean url_unreserved_char(int c) {
case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
case '-': case '.': case '_': case '~':
return true;
case ' ':
return !escapePlus;
default:
break;
}
Expand All @@ -263,7 +265,7 @@ static boolean url_unreserved_char(int c) {

static final byte[] upper_hexdigits = "0123456789ABCDEF".getBytes(RubyEncoding.UTF8);

static IRubyObject optimized_escape(Ruby runtime, RubyString str) {
static IRubyObject optimized_escape(Ruby runtime, RubyString str, boolean escapePlus) {
int i, len, beg = 0;
RubyString dest = null;
byte[] cstrBytes;
Expand All @@ -277,7 +279,7 @@ static IRubyObject optimized_escape(Ruby runtime, RubyString str) {

for (i = 0; i < len; ++i) {
int c = cstrBytes[cstr + i] & 0xFF;
if (!url_unreserved_char(c)) {
if (!url_unreserved_char(c, escapePlus)) {
if (dest == null) {
dest = RubyString.newStringLight(runtime, len);
}
Expand Down Expand Up @@ -305,7 +307,7 @@ static IRubyObject optimized_escape(Ruby runtime, RubyString str) {
}

static IRubyObject
optimized_unescape(ThreadContext context, RubyString str, IRubyObject encoding) {
optimized_unescape(ThreadContext context, RubyString str, IRubyObject encoding, boolean unescapePlus) {
int i, len, beg = 0;
RubyString dest = null;
byte[] cstrBytes;
Expand All @@ -331,7 +333,7 @@ static IRubyObject optimized_escape(Ruby runtime, RubyString str) {
buf = ((char_to_number(cstrBytes[cstr + i + 1]) << 4)
| char_to_number(cstrBytes[cstr + i + 2]));
clen = 2;
} else if (c == '+') {
} else if (unescapePlus && c == '+') {
buf = ' ';
} else {
continue;
Expand Down Expand Up @@ -416,7 +418,25 @@ public static IRubyObject cgiesc_escape(ThreadContext context, IRubyObject self,
RubyString str = _str.convertToString();

if (str.getEncoding().isAsciiCompatible()) {
return optimized_escape(context.runtime, str);
return optimized_escape(context.runtime, str, true);
} else {
return Helpers.invokeSuper(context, self, _str, Block.NULL_BLOCK);
}
}

/*
* call-seq:
* CGI.escapeURIComponent(string) -> string
*
* Returns URL-escaped string following RFC 3986.
*
*/
@JRubyMethod(name = "escapeURIComponent", alias = { "escape_uri_component" }, module = true, frame = true)
public static IRubyObject cgiesc_escape_uri_component(ThreadContext context, IRubyObject self, IRubyObject _str) {
RubyString str = _str.convertToString();

if (str.getEncoding().isAsciiCompatible()) {
return optimized_escape(context.runtime, str, false);
} else {
return Helpers.invokeSuper(context, self, _str, Block.NULL_BLOCK);
}
Expand All @@ -443,7 +463,28 @@ public static IRubyObject cgiesc_unescape(ThreadContext context, IRubyObject sel

if (str.getEncoding().isAsciiCompatible()) {
IRubyObject enc = accept_charset(argv, argv.length - 1, 1, self);
return optimized_unescape(context, str, enc);
return optimized_unescape(context, str, enc, true);
} else {
return Helpers.invokeSuper(context, self, argv, Block.NULL_BLOCK);
}
}

/*
* call-seq:
* CGI.unescapeURIComponent(string, encoding=@@accept_charset) -> string
*
* Returns URL-unescaped string following RFC 3986.
*
*/
@JRubyMethod(name = "unescapeURIComponent", alias = { "unescape_uri_component" }, required = 1, optional = 1, module = true, frame = true)
public static IRubyObject cgiesc_unescape_uri_component(ThreadContext context, IRubyObject self, IRubyObject[] argv) {
IRubyObject _str = argv[0];

RubyString str = _str.convertToString();

if (str.getEncoding().isAsciiCompatible()) {
IRubyObject enc = accept_charset(argv, argv.length - 1, 1, self);
return optimized_unescape(context, str, enc, false);
} else {
return Helpers.invokeSuper(context, self, argv, Block.NULL_BLOCK);
}
Expand Down

0 comments on commit c90c9ea

Please sign in to comment.