11#include "ruby.h"
22#include "ruby/encoding.h"
3+ #include <stdbool.h>
34
45RUBY_EXTERN unsigned long ruby_scan_digits (const char * str , ssize_t len , int base , size_t * retlen , int * overflow );
56RUBY_EXTERN const char ruby_hexdigits [];
@@ -200,7 +201,7 @@ url_unreserved_char(unsigned char c)
200201}
201202
202203static VALUE
203- optimized_escape (VALUE str )
204+ optimized_escape (VALUE str , bool plus_escape )
204205{
205206 long i , len , beg = 0 ;
206207 VALUE dest = 0 ;
@@ -220,7 +221,7 @@ optimized_escape(VALUE str)
220221 rb_str_cat (dest , cstr + beg , i - beg );
221222 beg = i + 1 ;
222223
223- if (c == ' ' ) {
224+ if (plus_escape && c == ' ' ) {
224225 rb_str_cat_cstr (dest , "+" );
225226 }
226227 else {
@@ -242,7 +243,7 @@ optimized_escape(VALUE str)
242243}
243244
244245static VALUE
245- optimized_unescape (VALUE str , VALUE encoding )
246+ optimized_unescape (VALUE str , VALUE encoding , int unescape_plus )
246247{
247248 long i , len , beg = 0 ;
248249 VALUE dest = 0 ;
@@ -265,7 +266,7 @@ optimized_unescape(VALUE str, VALUE encoding)
265266 | char_to_number (cstr [i + 2 ]));
266267 clen = 2 ;
267268 }
268- else if (c == '+' ) {
269+ else if (unescape_plus && c == '+' ) {
269270 buf [0 ] = ' ' ;
270271 }
271272 else {
@@ -348,7 +349,7 @@ cgiesc_unescape_html(VALUE self, VALUE str)
348349 * call-seq:
349350 * CGI.escape(string) -> string
350351 *
351- * Returns URL-escaped string.
352+ * Returns URL-escaped string (+application/x-www-form-urlencoded+) .
352353 *
353354 */
354355static VALUE
@@ -357,7 +358,7 @@ cgiesc_escape(VALUE self, VALUE str)
357358 StringValue (str );
358359
359360 if (rb_enc_str_asciicompat_p (str )) {
360- return optimized_escape (str );
361+ return optimized_escape (str , true );
361362 }
362363 else {
363364 return rb_call_super (1 , & str );
@@ -376,7 +377,7 @@ accept_charset(int argc, VALUE *argv, VALUE self)
376377 * call-seq:
377378 * CGI.unescape(string, encoding=@@accept_charset) -> string
378379 *
379- * Returns URL-unescaped string.
380+ * Returns URL-unescaped string (+application/x-www-form-urlencoded+) .
380381 *
381382 */
382383static VALUE
@@ -388,7 +389,50 @@ cgiesc_unescape(int argc, VALUE *argv, VALUE self)
388389
389390 if (rb_enc_str_asciicompat_p (str )) {
390391 VALUE enc = accept_charset (argc - 1 , argv + 1 , self );
391- return optimized_unescape (str , enc );
392+ return optimized_unescape (str , enc , 1 );
393+ }
394+ else {
395+ return rb_call_super (argc , argv );
396+ }
397+ }
398+
399+ /*
400+ * call-seq:
401+ * CGI.escapeURIComponent(string) -> string
402+ *
403+ * Returns URL-escaped string following RFC 3986.
404+ *
405+ */
406+ static VALUE
407+ cgiesc_escape_uri_component (VALUE self , VALUE str )
408+ {
409+ StringValue (str );
410+
411+ if (rb_enc_str_asciicompat_p (str )) {
412+ return optimized_escape (str , false);
413+ }
414+ else {
415+ return rb_call_super (1 , & str );
416+ }
417+ }
418+
419+ /*
420+ * call-seq:
421+ * CGI.unescapeURIComponent(string, encoding=@@accept_charset) -> string
422+ *
423+ * Returns URL-unescaped string following RFC 3986.
424+ *
425+ */
426+ static VALUE
427+ cgiesc_unescape_uri_component (int argc , VALUE * argv , VALUE self )
428+ {
429+ VALUE str = (rb_check_arity (argc , 1 , 2 ), argv [0 ]);
430+
431+ StringValue (str );
432+
433+ if (rb_enc_str_asciicompat_p (str )) {
434+ VALUE enc = accept_charset (argc - 1 , argv + 1 , self );
435+ return optimized_unescape (str , enc , 0 );
392436 }
393437 else {
394438 return rb_call_super (argc , argv );
@@ -414,6 +458,8 @@ InitVM_escape(void)
414458 rb_mUtil = rb_define_module_under (rb_cCGI , "Util" );
415459 rb_define_method (rb_mEscape , "escapeHTML" , cgiesc_escape_html , 1 );
416460 rb_define_method (rb_mEscape , "unescapeHTML" , cgiesc_unescape_html , 1 );
461+ rb_define_method (rb_mEscape , "escapeURIComponent" , cgiesc_escape_uri_component , 1 );
462+ rb_define_method (rb_mEscape , "unescapeURIComponent" , cgiesc_unescape_uri_component , -1 );
417463 rb_define_method (rb_mEscape , "escape" , cgiesc_escape , 1 );
418464 rb_define_method (rb_mEscape , "unescape" , cgiesc_unescape , -1 );
419465 rb_prepend_module (rb_mUtil , rb_mEscape );
0 commit comments