@@ -200,7 +200,7 @@ url_unreserved_char(unsigned char c)
200200}
201201
202202static VALUE
203- optimized_escape (VALUE str )
203+ optimized_escape (VALUE str , int plus_escape )
204204{
205205 long i , len , beg = 0 ;
206206 VALUE dest = 0 ;
@@ -220,7 +220,7 @@ optimized_escape(VALUE str)
220220 rb_str_cat (dest , cstr + beg , i - beg );
221221 beg = i + 1 ;
222222
223- if (c == ' ' ) {
223+ if (plus_escape && c == ' ' ) {
224224 rb_str_cat_cstr (dest , "+" );
225225 }
226226 else {
@@ -242,7 +242,7 @@ optimized_escape(VALUE str)
242242}
243243
244244static VALUE
245- optimized_unescape (VALUE str , VALUE encoding )
245+ optimized_unescape (VALUE str , VALUE encoding , int unescape_plus )
246246{
247247 long i , len , beg = 0 ;
248248 VALUE dest = 0 ;
@@ -265,7 +265,7 @@ optimized_unescape(VALUE str, VALUE encoding)
265265 | char_to_number (cstr [i + 2 ]));
266266 clen = 2 ;
267267 }
268- else if (c == '+' ) {
268+ else if (unescape_plus && c == '+' ) {
269269 buf [0 ] = ' ' ;
270270 }
271271 else {
@@ -348,7 +348,7 @@ cgiesc_unescape_html(VALUE self, VALUE str)
348348 * call-seq:
349349 * CGI.escape(string) -> string
350350 *
351- * Returns URL-escaped string.
351+ * Returns URL-escaped string (+application/x-www-form-urlencoded+) .
352352 *
353353 */
354354static VALUE
@@ -357,7 +357,7 @@ cgiesc_escape(VALUE self, VALUE str)
357357 StringValue (str );
358358
359359 if (rb_enc_str_asciicompat_p (str )) {
360- return optimized_escape (str );
360+ return optimized_escape (str , 1 );
361361 }
362362 else {
363363 return rb_call_super (1 , & str );
@@ -376,7 +376,7 @@ accept_charset(int argc, VALUE *argv, VALUE self)
376376 * call-seq:
377377 * CGI.unescape(string, encoding=@@accept_charset) -> string
378378 *
379- * Returns URL-unescaped string.
379+ * Returns URL-unescaped string (+application/x-www-form-urlencoded+) .
380380 *
381381 */
382382static VALUE
@@ -388,7 +388,50 @@ cgiesc_unescape(int argc, VALUE *argv, VALUE self)
388388
389389 if (rb_enc_str_asciicompat_p (str )) {
390390 VALUE enc = accept_charset (argc - 1 , argv + 1 , self );
391- return optimized_unescape (str , enc );
391+ return optimized_unescape (str , enc , 1 );
392+ }
393+ else {
394+ return rb_call_super (argc , argv );
395+ }
396+ }
397+
398+ /*
399+ * call-seq:
400+ * CGI.escapeURIComponent(string) -> string
401+ *
402+ * Returns URL-escaped string following RFC 3986.
403+ *
404+ */
405+ static VALUE
406+ cgiesc_escape_uri_component (VALUE self , VALUE str )
407+ {
408+ StringValue (str );
409+
410+ if (rb_enc_str_asciicompat_p (str )) {
411+ return optimized_escape (str , 1 );
412+ }
413+ else {
414+ return rb_call_super (1 , & str );
415+ }
416+ }
417+
418+ /*
419+ * call-seq:
420+ * CGI.unescapeURIComponent(string, encoding=@@accept_charset) -> string
421+ *
422+ * Returns URL-unescaped string following RFC 3986.
423+ *
424+ */
425+ static VALUE
426+ cgiesc_unescape_uri_component (int argc , VALUE * argv , VALUE self )
427+ {
428+ VALUE str = (rb_check_arity (argc , 1 , 2 ), argv [0 ]);
429+
430+ StringValue (str );
431+
432+ if (rb_enc_str_asciicompat_p (str )) {
433+ VALUE enc = accept_charset (argc - 1 , argv + 1 , self );
434+ return optimized_unescape (str , enc , 0 );
392435 }
393436 else {
394437 return rb_call_super (argc , argv );
@@ -414,6 +457,8 @@ InitVM_escape(void)
414457 rb_mUtil = rb_define_module_under (rb_cCGI , "Util" );
415458 rb_define_method (rb_mEscape , "escapeHTML" , cgiesc_escape_html , 1 );
416459 rb_define_method (rb_mEscape , "unescapeHTML" , cgiesc_unescape_html , 1 );
460+ rb_define_method (rb_mEscape , "escapeURIComponent" , cgiesc_escape_uri_component , 1 );
461+ rb_define_method (rb_mEscape , "unescapeURIComponent" , cgiesc_unescape_uri_component , -1 );
417462 rb_define_method (rb_mEscape , "escape" , cgiesc_escape , 1 );
418463 rb_define_method (rb_mEscape , "unescape" , cgiesc_unescape , -1 );
419464 rb_prepend_module (rb_mUtil , rb_mEscape );
0 commit comments