[前][次][番号順一覧][スレッド一覧]

ruby-changes:17845

From: shyouhei <ko1@a...>
Date: Mon, 22 Nov 2010 16:29:32 +0900 (JST)
Subject: [ruby-changes:17845] Ruby:r29856 (ruby_1_8_7): Thu, 8 Jul 2010 04:44:58 +0000 nahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>

shyouhei	2010-11-22 16:21:45 +0900 (Mon, 22 Nov 2010)

  New Revision: 29856

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=29856

  Log:
    Thu, 8 Jul 2010 04:44:58 +0000  nahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
     merge revision(s) 28575,28620:28632:
     
     	* test/openssl/test_config.c: added tests for all Config methods.
    
    git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28575 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
    Signed-off-by: URABE, Shyouhei <shyouhei@r...>
    
    * ext/openssl/ossl_config.c (ossl_config_copy): wrongly updating the
      given object with uninitialized CONF data.  now
      OpenSSL::Config#clone works as expected; cloning the config instead of
      SEGV or empty definition.
    
    * test/openssl/test_config.rb: added tests for Config#clone.
    
    git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28621 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
    Signed-off-by: URABE, Shyouhei <shyouhei@r...>
    
    * ext/openssl/ossl_config.c, ext/openssl/lib/openssl/config.rb,
      ext/openssl/lib/openssl.rb: reimplement OpenSSL::Config in Ruby. Now
      it should work on windows.
    
    * test/openssl/test_config.rb: added tests for OpenSSL::Config#dup.
    
    git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28632 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
    Signed-off-by: URABE, Shyouhei <shyouhei@r...>
    
     create mode 100644 ext/openssl/lib/openssl/config.rb
     create mode 100644 test/openssl/test_config.rb

  Added files:
    branches/ruby_1_8_7/ext/openssl/lib/openssl/config.rb
    branches/ruby_1_8_7/test/openssl/test_config.rb
  Modified files:
    branches/ruby_1_8_7/ChangeLog
    branches/ruby_1_8_7/ext/openssl/lib/openssl.rb
    branches/ruby_1_8_7/ext/openssl/ossl_config.c
    branches/ruby_1_8_7/test/openssl/utils.rb
    branches/ruby_1_8_7/version.h

Index: ruby_1_8_7/ext/openssl/ossl_config.c
===================================================================
--- ruby_1_8_7/ext/openssl/ossl_config.c	(revision 29855)
+++ ruby_1_8_7/ext/openssl/ossl_config.c	(revision 29856)
@@ -10,22 +10,6 @@
  */
 #include "ossl.h"
 
-#define WrapConfig(klass, obj, conf) do { \
-    if (!conf) { \
-	ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \
-    } \
-    obj = Data_Wrap_Struct(klass, 0, NCONF_free, conf); \
-} while (0)
-#define GetConfig(obj, conf) do { \
-    Data_Get_Struct(obj, CONF, conf); \
-    if (!conf) { \
-	ossl_raise(rb_eRuntimeError, "Config wasn't intitialized!"); \
-    } \
-} while (0)
-#define SafeGetConfig(obj, conf) do { \
-    OSSL_Check_Kind(obj, cConfig); \
-    GetConfig(obj, conf); \
-} while(0);
 
 /*
  * Classes
@@ -39,46 +23,31 @@
 
 static CONF *parse_config(VALUE, CONF*);
 
+/*
+ * GetConfigPtr is a public C-level function for getting OpenSSL CONF struct
+ * from an OpenSSL::Config(eConfig) instance.  We decided to implement
+ * OpenSSL::Config in Ruby level but we need to pass native CONF struct for
+ * some OpenSSL features such as X509V3_EXT_*.
+ */
 CONF *
 GetConfigPtr(VALUE obj)
 {
     CONF *conf;
-
-    SafeGetConfig(obj, conf);
-
-    return conf;
-}
-
-CONF *
-DupConfigPtr(VALUE obj)
-{
     VALUE str;
-
-    OSSL_Check_Kind(obj, cConfig);
-    str = rb_funcall(obj, rb_intern("to_s"), 0);
-
-    return parse_config(str, NULL);
-}
-
-/*
- * Private
- */
-static CONF *
-parse_config(VALUE str, CONF *dst)
-{
-    CONF *conf;
     BIO *bio;
     long eline = -1;
 
+    OSSL_Check_Kind(obj, cConfig);
+    str = rb_funcall(obj, rb_intern("to_s"), 0);
     bio = ossl_obj2bio(str);
-    conf = dst ? dst : NCONF_new(NULL);
+    conf = NCONF_new(NULL);
     if(!conf){
 	BIO_free(bio);
 	ossl_raise(eConfigError, NULL);
     }
     if(!NCONF_load_bio(conf, bio, &eline)){
 	BIO_free(bio);
-	if(!dst) NCONF_free(conf);
+	NCONF_free(conf);
 	if (eline <= 0) ossl_raise(eConfigError, "wrong config format");
 	else ossl_raise(eConfigError, "error in line %d", eline);
 	ossl_raise(eConfigError, NULL);
@@ -88,379 +57,7 @@
     return conf;
 }
 
-static VALUE
-ossl_config_s_parse(VALUE klass, VALUE str)
-{
-    CONF *conf;
-    VALUE obj;
-
-    conf = parse_config(str, NULL);
-    WrapConfig(klass, obj, conf);
-
-    return obj;
-}
-
-static VALUE
-ossl_config_s_alloc(VALUE klass)
-{
-    CONF *conf;
-    VALUE obj;
-
-    if(!(conf = NCONF_new(NULL)))
-	ossl_raise(eConfigError, NULL);
-    WrapConfig(klass, obj, conf);
-
-    return obj;
-}
-
-static VALUE
-ossl_config_copy(VALUE self, VALUE other)
-{
-    VALUE str;
-    CONF *conf;
-
-    str = rb_funcall(self, rb_intern("to_s"), 0);
-    GetConfig(other, conf);
-    parse_config(str, conf);
-
-    return self;
-}
-
-static VALUE
-ossl_config_initialize(int argc, VALUE *argv, VALUE self)
-{
-    CONF *conf;
-    long eline = -1;
-    char *filename;
-    VALUE path;
-
-    rb_scan_args(argc, argv, "01", &path);
-    if(!NIL_P(path)){
-	SafeStringValue(path);
-        filename = StringValuePtr(path);
-	GetConfig(self, conf);
-	if (!NCONF_load(conf, filename, &eline)){
-	    if (eline <= 0)
-		ossl_raise(eConfigError, "wrong config file %s", filename);
-	    else
-		ossl_raise(eConfigError, "error in %s:%d", filename, eline);
-        }
-    }
-#ifdef OSSL_NO_CONF_API
-    else rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
-#else
-    else {
-	GetConfig(self, conf);
-	_CONF_new_data(conf);
-    }
-#endif
-    
-    return self;
-}
-
-static VALUE
-ossl_config_add_value(VALUE self, VALUE section, VALUE name, VALUE value)
-{
-#ifdef OSSL_NO_CONF_API
-    rb_notimplement();
-#else
-    CONF *conf;
-    CONF_VALUE *sv, *cv;
-
-    StringValue(section);
-    StringValue(name);
-    StringValue(value);
-    GetConfig(self, conf);
-    if(!(sv = _CONF_get_section(conf, RSTRING_PTR(section)))){
-	if(!(sv = _CONF_new_section(conf, RSTRING_PTR(section)))){
-	    ossl_raise(eConfigError, NULL);
-	}
-    }
-    if(!(cv = OPENSSL_malloc(sizeof(CONF_VALUE)))){
-	ossl_raise(eConfigError, NULL);
-    }
-    cv->name = BUF_strdup(RSTRING_PTR(name));
-    cv->value = BUF_strdup(RSTRING_PTR(value));
-    if(!cv->name || !cv->value || !_CONF_add_string(conf, sv, cv)){
-	OPENSSL_free(cv->name);
-	OPENSSL_free(cv->value);
-	OPENSSL_free(cv);
-	ossl_raise(eConfigError, "_CONF_add_string failure");
-    }
-    
-    return value;
-#endif
-}
-
-static void
-rb_ossl_config_modify_check(VALUE config)
-{
-    if (OBJ_FROZEN(config)) rb_error_frozen("OpenSSL::Config");
-    if (!OBJ_TAINTED(config) && rb_safe_level() >= 4)
-	rb_raise(rb_eSecurityError, "Insecure: can't modify OpenSSL config");
-}
-
-static VALUE
-ossl_config_add_value_m(VALUE self, VALUE section, VALUE name, VALUE value)
-{
-#if defined(OSSL_NO_CONF_API)
-    rb_notimplement();
-#else
-    rb_ossl_config_modify_check(self);
-    return ossl_config_add_value(self, section, name, value);
-#endif
-}
-
-static VALUE
-ossl_config_get_value(VALUE self, VALUE section, VALUE name)
-{
-    CONF *conf;
-    char *str;
-
-    StringValue(section);
-    StringValue(name);
-    GetConfig(self, conf);
-    str = NCONF_get_string(conf, RSTRING_PTR(section), RSTRING_PTR(name));
-    if(!str){
-	ERR_clear_error();
-	return Qnil;
-    }
-
-    return rb_str_new2(str);
-}
-
-static VALUE
-ossl_config_get_value_old(int argc, VALUE *argv, VALUE self)
-{
-    VALUE section, name;
-    
-    rb_scan_args(argc, argv, "11", &section, &name);
-
-    /* support conf.value(nil, "HOME") -> conf.get_value("", "HOME") */
-    if (NIL_P(section)) section = rb_str_new2("");
-    /* support conf.value("HOME") -> conf.get_value("", "HOME") */
-    if (NIL_P(name)) {
-	name = section;
-	section = rb_str_new2("");
-    }
-    /* NOTE: Don't care about conf.get_value(nil, nil) */
-    rb_warn("Config#value is deprecated; use Config#get_value");
-    return ossl_config_get_value(self, section, name);
-}
-
-static VALUE
-set_conf_section_i(VALUE i, VALUE *arg)
-{
-    VALUE name, value;
-
-    Check_Type(i, T_ARRAY);
-    name = rb_ary_entry(i, 0);
-    value = rb_ary_entry(i, 1);
-    ossl_config_add_value(arg[0], arg[1], name, value);
-
-    return Qnil;
-}
-
-static VALUE
-ossl_config_set_section(VALUE self, VALUE section, VALUE hash)
-{
-    VALUE arg[2];
-
-    rb_ossl_config_modify_check(self);
-    arg[0] = self;
-    arg[1] = section;
-    rb_block_call(hash, rb_intern("each"), 0, 0, set_conf_section_i, (VALUE)arg);
-    return hash;
-}
-
 /*
- * Get all numbers as strings - use str.to_i to convert
- * long number = CONF_get_number(confp->config, sect, StringValuePtr(item));
- */
-static VALUE
-ossl_config_get_section(VALUE self, VALUE section)
-{
-    CONF *conf;
-    STACK_OF(CONF_VALUE) *sk;
-    CONF_VALUE *entry;
-    int i, entries;
-    VALUE hash;
-
-    hash = rb_hash_new();
-    StringValue(section);
-    GetConfig(self, conf);
-    if (!(sk = NCONF_get_section(conf, StringValuePtr(section)))) {
-	ERR_clear_error();
-	return hash;
-    }
-    if ((entries = sk_CONF_VALUE_num(sk)) < 0) {
-	OSSL_Debug("# of items in section is < 0?!?");
-	return hash;
-    }
-    for (i=0; i<entries; i++) {
-	entry = sk_CONF_VALUE_value(sk, i);		
-	rb_hash_aset(hash, rb_str_new2(entry->name), rb_str_new2(entry->value));
-    }
-
-    return hash;
-}
-
-static VALUE
-ossl_config_get_section_old(VALUE self, VALUE section)
-{
-    rb_warn("Config#section is deprecated; use Config#[]");
-    return ossl_config_get_section(self, section);
-}
-
-#ifdef IMPLEMENT_LHASH_DOALL_ARG_FN
-#define IMPLEMENT_LHASH_DOALL_ARG_FN_098(f_name,o_type,a_type) \
-            void f_name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \
-		                o_type a = (o_type)arg1; \
-		                a_type b = (a_type)arg2; \
-		                f_name(a,b); }
-
-static void
-get_conf_section(CONF_VALUE *cv, VALUE ary)
-{
-    if(cv->name) return;
-    rb_ary_push(ary, rb_str_new2(cv->section));
-}
-
-static IMPLEMENT_LHASH_DOALL_ARG_FN_098(get_conf_section, CONF_VALUE*, VALUE)
-
-static VALUE
-ossl_config_get_sections(VALUE self)
-{
-    CONF *conf;
-    VALUE ary;
-
-    GetConfig(self, conf);
-    ary = rb_ary_new();
-    lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(get_conf_section), (void*)ary);
-
-    return ary;
-}
-
-static void
-dump_conf_value(CONF_VALUE *cv, VALUE str)
-{
-    STACK_OF(CONF_VALUE) *sk;
-    CONF_VALUE *v;
-    int i, num;
-
-    if (cv->name) return;
-    sk = (STACK_OF(CONF_VALUE)*)cv->value;
-    num = sk_CONF_VALUE_num(sk);
-    rb_str_cat2(str, "[ ");
-    rb_str_cat2(str, cv->section);
-    rb_str_cat2(str, " ]\n");
-    for(i = 0; i < num; i++){
-	v = sk_CONF_VALUE_value(sk, i);
-	rb_str_cat2(str, v->name ? v->name : "None");
-	rb_str_cat2(str, "=");
-	rb_str_cat2(str, v->value ? v->value : "None");
-	rb_str_cat2(str, "\n");
-    }
-    rb_str_cat2(str, "\n");
-}
-
-static IMPLEMENT_LHASH_DOALL_ARG_FN_098(dump_conf_value, CONF_VALUE*, VALUE)
-
-static VALUE
-dump_conf(CONF *conf)
-{
-    VALUE str;
-
-    str = rb_str_new(0, 0);
-    lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(dump_conf_value), (void*)str);
-
-    return str;
-}
-
-static VALUE
-ossl_config_to_s(VALUE self)
-{
-    CONF *conf;
-
-    GetConfig(self, conf);
-
-    return dump_conf(conf);
-}
-
-static void
-each_conf_value(CONF_VALUE *cv, void* dummy)
-{
-    STACK_OF(CONF_VALUE) *sk;
-    CONF_VALUE *v;
-    VALUE section, name, value, args;
-    int i, num;
-
-    if (cv->name) return;
-    sk = (STACK_OF(CONF_VALUE)*)cv->value;
-    num = sk_CONF_VALUE_num(sk);
-    section = rb_str_new2(cv->section);
-    for(i = 0; i < num; i++){
-	v = sk_CONF_VALUE_value(sk, i);
-	name = v->name ? rb_str_new2(v->name) : Qnil;
-	value = v->value ? rb_str_new2(v->value) : Qnil;
-        args = rb_ary_new3(3, section, name, value);
-	rb_yield(args);
-    }
-}
-
-static IMPLEMENT_LHASH_DOALL_ARG_FN_098(each_conf_value, CONF_VALUE*, void*)
-
-static VALUE
-ossl_config_each(VALUE self)
-{
-    CONF *conf;
-
-    RETURN_ENUMERATOR(self, 0, 0);
-
-    GetConfig(self, conf);
-    lh_doall_arg(conf->data, LHASH_DOALL_ARG_FN(each_conf_value), (void*)NULL);
-
-    return self;
-}
-#else
-static VALUE
-ossl_config_get_sections(VALUE self)
-{
-    rb_warn("#sections don't work with %s", OPENSSL_VERSION_TEXT);
-    return rb_ary_new();
-}
-
-static VALUE
-ossl_config_to_s(VALUE self)
-{
-    rb_warn("#to_s don't work with %s", OPENSSL_VERSION_TEXT);
-    return rb_str_new(0, 0);
-}
-
-static VALUE
-ossl_config_each(VALUE self)
-{
-    rb_warn("#each don't work with %s", OPENSSL_VERSION_TEXT);
-    return self;
-}
-#endif
-
-static VALUE
-ossl_config_inspect(VALUE self)
-{
-    VALUE str, ary = ossl_config_get_sections(self);
-    char *cname = rb_class2name(rb_obj_class(self));
-
-    str = rb_str_new2("#<");
-    rb_str_cat2(str, cname);
-    rb_str_cat2(str, " sections=");
-    rb_str_append(str, rb_inspect(ary));
-    rb_str_cat2(str, ">");
-
-    return str;
-}
-
-/*
  * INIT
  */
 void
@@ -474,20 +71,5 @@
     rb_define_const(cConfig, "DEFAULT_CONFIG_FILE",
 		    rb_str_new2(default_config_file));
     OPENSSL_free(default_config_file);
-    rb_include_module(cConfig, rb_mEnumerable);
-    rb_define_singleton_method(cConfig, "parse", ossl_config_s_parse, 1);
-    rb_define_alias(CLASS_OF(cConfig), "load", "new");
-    rb_define_alloc_func(cConfig, ossl_config_s_alloc);
-    rb_define_copy_func(cConfig, ossl_config_copy);
-    rb_define_method(cConfig, "initialize", ossl_config_initialize, -1);
-    rb_define_method(cConfig, "get_value", ossl_config_get_value, 2);
-    rb_define_method(cConfig, "value", ossl_config_get_value_old, -1);
-    rb_define_method(cConfig, "add_value", ossl_config_add_value_m, 3);
-    rb_define_method(cConfig, "[]", ossl_config_get_section, 1);
-    rb_define_method(cConfig, "section", ossl_config_get_section_old, 1);
-    rb_define_method(cConfig, "[]=", ossl_config_set_section, 2);
-    rb_define_method(cConfig, "sections", ossl_config_get_sections, 0);
-    rb_define_method(cConfig, "to_s", ossl_config_to_s, 0);
-    rb_define_method(cConfig, "each", ossl_config_each, 0);
-    rb_define_method(cConfig, "inspect", ossl_config_inspect, 0);
+    /* methods are defined by openssl/config.rb */
 }
Index: ruby_1_8_7/ext/openssl/lib/openssl/config.rb
===================================================================
--- ruby_1_8_7/ext/openssl/lib/openssl/config.rb	(revision 0)
+++ ruby_1_8_7/ext/openssl/lib/openssl/config.rb	(revision 29856)
@@ -0,0 +1,316 @@
+=begin
+= Ruby-space definitions that completes C-space funcs for Config
+
+= Info
+  Copyright (C) 2010  Hiroshi Nakamura <nahi@r...>
+
+= Licence
+  This program is licenced under the same licence as Ruby.
+  (See the file 'LICENCE'.)
+
+=end
+
+##
+# Should we care what if somebody require this file directly?
+#require 'openssl'
+require 'stringio'
+
+module OpenSSL
+  class Config
+    include Enumerable
+
+    class << self
+      def parse(str)
+        c = new()
+        parse_config(StringIO.new(str)).each do |section, hash|
+          c[section] = hash
+        end
+        c
+      end
+
+      alias load new
+
+      def parse_config(io)
+        begin
+          parse_config_lines(io)
+        rescue ConfigError => e
+          e.message.replace("error in line #{io.lineno}: " + e.message)
+          raise
+        end
+      end
+
+      def get_key_string(data, section, key) # :nodoc:
+        if v = data[section] && data[section][key]
+          return v
+        elsif section == 'ENV'
+          if v = ENV[key]
+            return v
+          end
+        end
+        if v = data['default'] && data['default'][key]
+          return v
+        end
+      end
+
+    private
+
+      def parse_config_lines(io)
+        section = 'default'
+        data = {section => {}}
+        while definition = get_definition(io)
+          definition = clear_comments(definition)
+          next if definition.empty?
+          if definition[0] == ?[
+            if /\[([^\]]*)\]/ =~ definition
+              section = $1.strip
+              data[section] ||= {}
+            else
+              raise ConfigError, "missing close square bracket"
+            end
+          else
+            if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
+              if $2
+                section = $1
+                key = $2
+              else
+                key = $1
+              end
+              value = unescape_value(data, section, $3)
+              (data[section] ||= {})[key] = value.strip
+            else
+              raise ConfigError, "missing equal sign"
+            end
+          end
+        end
+        data
+      end
+
+      # escape with backslash
+      QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
+      # escape with backslash and doubled dq
+      QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
+      # escaped char map
+      ESCAPE_MAP = {
+        "r" => "\r",
+        "n" => "\n",
+        "b" => "\b",
+        "t" => "\t",
+      }
+
+      def unescape_value(data, section, value)
+        scanned = []
+        while m = value.match(/['"\\$]/)
+          scanned << m.pre_match
+          c = m[0]
+          value = m.post_match
+          case c
+          when "'"
+            if m = value.match(QUOTE_REGEXP_SQ)
+              scanned << m[1].gsub(/\\(.)/, '\\1')
+              value = m.post_match
+            else
+              break
+            end
+          when '"'
+            if m = value.match(QUOTE_REGEXP_DQ)
+              scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
+              value = m.post_match
+            else
+              break
+            end
+          when "\\"
+            c = value.slice!(0, 1)
+            scanned << (ESCAPE_MAP[c] || c)
+          when "$"
+            ref, value = extract_reference(value)
+            refsec = section
+            if ref.index('::')
+              refsec, ref = ref.split('::', 2)
+            end
+            if v = get_key_string(data, refsec, ref)
+              scanned << v
+            else
+              raise ConfigError, "variable has no value"
+            end
+          else
+            raise 'must not reaced'
+          end
+        end
+        scanned << value
+        scanned.join
+      end
+
+      def extract_reference(value)
+        rest = ''
+        if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
+          value = m[1] || m[2]
+          rest = m.post_match
+        elsif [?(, ?{].include?(value[0])
+          raise ConfigError, "no close brace"
+        end
+        if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
+          return m[0], m.post_match + rest
+        else
+          raise
+        end
+      end
+
+      def clear_comments(line)
+        # FCOMMENT
+        if m = line.match(/\A([\t\n\f ]*);.*\z/)
+          return m[1]
+        end
+        # COMMENT
+        scanned = []
+        while m = line.match(/[#'"\\]/)
+          scanned << m.pre_match
+          c = m[0]
+          line = m.post_match
+          case c
+          when '#'
+            line = nil
+            break
+          when "'", '"'
+            regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
+            scanned << c
+            if m = line.match(regexp)
+              scanned << m[0]
+              line = m.post_match
+            else
+              scanned << line
+              line = nil
+              break
+            end
+          when "\\"
+            scanned << c
+            scanned << line.slice!(0, 1)
+          else
+            raise 'must not reaced'
+          end
+        end
+        scanned << line
+        scanned.join
+      end
+
+      def get_definition(io)
+        if line = get_line(io)
+          while /[^\\]\\\z/ =~ line
+            if extra = get_line(io)
+              line += extra
+            else
+              break
+            end
+          end
+          return line.strip
+        end
+      end
+
+      def get_line(io)
+        if line = io.gets
+          line.gsub(/[\r\n]*/, '')
+        end
+      end
+    end
+
+    def initialize(filename = nil)
+      @data = {}
+      if filename
+        File.open(filename.to_s) do |file|
+          Config.parse_config(file).each do |section, hash|
+            self[section] = hash
+          end
+        end
+      end
+    end
+
+    def get_value(section, key)
+      if section.nil?
+        raise TypeError.new('nil not allowed')
+      end
+      section = 'default' if section.empty?
+      get_key_string(section, key)
+    end
+
+    def value(arg1, arg2 = nil)
+      warn('Config#value is deprecated; use Config#get_value')
+      if arg2.nil?
+        section, key = 'default', arg1
+      else
+        section, key = arg1, arg2
+      end
+      section ||= 'default'
+      section = 'default' if section.empty?
+      get_key_string(section, key)
+    end
+
+    def add_value(section, key, value)
+      check_modify
+      (@data[section] ||= {})[key] = value
+    end
+
+    def [](section)
+      @data[section] || {}
+    end
+
+    def section(name)
+      warn('Config#section is deprecated; use Config#[]')
+      @data[name] || {}
+    end
+
+    def []=(section, pairs)
+      check_modify
+      @data[section] ||= {}
+      pairs.each do |key, value|
+        self.add_value(section, key, value)
+      end
+    end
+
+    def sections
+      @data.keys
+    end
+
+    def to_s
+      ary = []
+      @data.keys.sort.each do |section|
+        ary << "[ #{section} ]\n"
+        @data[section].keys.each do |key|
+          ary << "#{key}=#{@data[section][key]}\n"
+        end
+        ary << "\n"
+      end
+      ary.join
+    end
+
+    def each
+      @data.each do |section, hash|
+        hash.each do |key, value|
+          yield(section, key, value)
+        end
+      end
+    end
+
+    def inspect
+      "#<#{self.class.name} sections=#{sections.inspect}>"
+    end
+
+  protected
+
+    def data
+      @data
+    end
+
+  private
+
+    def initialize_copy(other)
+      @data = other.data.dup
+    end
+
+    def check_modify
+      raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
+    end
+
+    def get_key_string(section, key)
+      Config.get_key_string(@data, section, key)
+    end
+  end
+end
Index: ruby_1_8_7/ext/openssl/lib/openssl.rb
===================================================================
--- ruby_1_8_7/ext/openssl/lib/openssl.rb	(revision 29855)
+++ ruby_1_8_7/ext/openssl/lib/openssl.rb	(revision 29856)
@@ -18,6 +18,7 @@
 
 require 'openssl/bn'
 require 'openssl/cipher'
+require 'openssl/config'
 require 'openssl/digest'
 require 'openssl/pkcs7'
 require 'openssl/ssl-internal'
Index: ruby_1_8_7/ChangeLog
===================================================================
--- ruby_1_8_7/ChangeLog	(revision 29855)
+++ ruby_1_8_7/ChangeLog	(revision 29856)
@@ -1,3 +1,24 @@
+Tue Jul 13 21:46:38 2010  NAKAMURA, Hiroshi  <nahi@r...>
+
+	* ext/openssl/ossl_config.c, ext/openssl/lib/openssl/config.rb,
+	  ext/openssl/lib/openssl.rb: reimplement OpenSSL::Config in Ruby. Now
+	  it should work on windows.
+
+	* test/openssl/test_config.rb: added tests for OpenSSL::Config#dup.
+
+Mon Jul 12 22:26:00 2010  NAKAMURA, Hiroshi  <nahi@r...>
+
+	* ext/openssl/ossl_config.c (ossl_config_copy): wrongly updating the
+	  given object with uninitialized CONF data.  now
+	  OpenSSL::Config#clone works as expected; cloning the config instead of
+	  SEGV or empty definition.
+
+	* test/openssl/test_config.rb: added tests for Config#clone.
+
+Thu Jul  8 13:43:13 2010  NAKAMURA, Hiroshi  <nahi@r...>
+
+	* test/openssl/test_config.c: added tests for all Config methods.
+
 Wed Jul  7 13:24:24 2010  NAKAMURA Usaku  <usa@r...>
 
 	* file.c (ruby_find_basename): set correct baselen.
Index: ruby_1_8_7/version.h
===================================================================
--- ruby_1_8_7/version.h	(revision 29855)
+++ ruby_1_8_7/version.h	(revision 29856)
@@ -2,7 +2,7 @@
 #define RUBY_RELEASE_DATE "2010-11-22"
 #define RUBY_VERSION_CODE 187
 #define RUBY_RELEASE_CODE 20101122
-#define RUBY_PATCHLEVEL 305
+#define RUBY_PATCHLEVEL 306
 
 #define RUBY_VERSION_MAJOR 1
 #define RUBY_VERSION_MINOR 8
Index: ruby_1_8_7/test/openssl/utils.rb
===================================================================
--- ruby_1_8_7/test/openssl/utils.rb	(revision 29855)
+++ ruby_1_8_7/test/openssl/utils.rb	(revision 29856)
@@ -132,4 +132,13 @@
     pkvalue   = publickey.value
     OpenSSL::Digest::SHA1.hexdigest(pkvalue).scan(/../).join(":").upcase
   end
+
+  def silent
+    begin
+      back, $VERBOSE = $VERBOSE, nil
+      yield
+    ensure
+      $VERBOSE = back if back
+    end
+  end
 end
Index: ruby_1_8_7/test/openssl/test_config.rb
===================================================================
--- ruby_1_8_7/test/openssl/test_config.rb	(revision 0)
+++ ruby_1_8_7/test/openssl/test_config.rb	(revision 29856)
@@ -0,0 +1,290 @@
+require 'openssl'
+require "test/unit"
+require 'tempfile'
+require File.join(File.dirname(__FILE__), "utils.rb")
+
+class OpenSSL::TestConfig < Test::Unit::TestCase
+  def setup
+    file = Tempfile.open("openssl.cnf")
+    file << <<__EOD__
+HOME = .
+[ ca ]
+default_ca = CA_default
+[ CA_default ]
+dir = ./demoCA
+certs                =                  ./certs
+__EOD__
+    file.close
+    @it = OpenSSL::Config.new(file.path)
+  end
+
+  def test_constants
+    assert(OpenSSL::Config.constants.include?('DEFAULT_CONFIG_FILE'))
+    assert_nothing_raised do
+      OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE)
+    end
+  end
+
+  def test_s_parse
+    c = OpenSSL::Config.parse('')
+    assert_equal("[ default ]\n\n", c.to_s)
+    c = OpenSSL::Config.parse(@it.to_s)
+    assert_equal(['CA_default', 'ca', 'default'], c.sections.sort)
+  end
+
+  def test_s_parse_format
+    c = OpenSSL::Config.parse(<<__EOC__)
+ baz =qx\t                # "baz = qx"
+
+foo::bar = baz            # shortcut section::key format
+  default::bar = baz      # ditto
+a=\t \t                   # "a = ": trailing spaces are ignored
+ =b                       # " = b": empty key
+ =c                       # " = c": empty key (override the above line)
+    d=                    # "c = ": trailing comment is ignored
+
+sq = 'foo''b\\'ar'
+    dq ="foo""''\\""
+    dq2 = foo""bar
+esc=a\\r\\n\\b\\tb
+foo\\bar = foo\\b\\\\ar
+foo\\bar::foo\\bar = baz
+[default1  default2]\t\t  # space is allowed in section name
+          fo =b  ar       # space allowed in value
+[emptysection]
+ [doller ]
+foo=bar
+bar = $(foo)
+baz = 123$(default::bar)456${foo}798
+qux = ${baz}
+quxx = $qux.$qux
+__EOC__
+    assert_equal(['default', 'default1  default2', 'doller', 'emptysection', 'foo', 'foo\\bar'], c.sections.sort)
+    assert_equal(['', 'a', 'bar', 'baz', 'd', 'dq', 'dq2', 'esc', 'foo\\bar', 'sq'], c['default'].keys.sort)
+    assert_equal('c', c['default'][''])
+    assert_equal('', c['default']['a'])
+    assert_equal('qx', c['default']['baz'])
+    assert_equal('', c['default']['d'])
+    assert_equal('baz', c['default']['bar'])
+    assert_equal("foob'ar", c['default']['sq'])
+    assert_equal("foo''\"", c['default']['dq'])
+    assert_equal("foobar", c['default']['dq2'])
+    assert_equal("a\r\n\b\tb", c['default']['esc'])
+    assert_equal("foo\b\\ar", c['default']['foo\\bar'])
+    assert_equal('baz', c['foo']['bar'])
+    assert_equal('baz', c['foo\\bar']['foo\\bar'])
+    assert_equal('b  ar', c['default1  default2']['fo'])
+
+    # dolloer
+    assert_equal('bar', c['doller']['foo'])
+    assert_equal('bar', c['doller']['bar'])
+    assert_equal('123baz456bar798', c['doller']['baz'])
+    assert_equal('123baz456bar798', c['doller']['qux'])
+    assert_equal('123baz456bar798.123baz456bar798', c['doller']['quxx'])
+
+    excn = assert_raise(OpenSSL::ConfigError) do
+      OpenSSL::Config.parse("foo = $bar")
+    end
+    assert_equal("error in line 1: variable has no value", excn.message)
+
+    excn = assert_raise(OpenSSL::ConfigError) do
+      OpenSSL::Config.parse("foo = $(bar")
+    end
+    assert_equal("error in line 1: no close brace", excn.message)
+
+    excn = assert_raise(OpenSSL::ConfigError) do
+      OpenSSL::Config.parse("f o =b  ar      # no space in key")
+    end
+    assert_equal("error in line 1: missing equal sign", excn.message)
+
+    excn = assert_raise(OpenSSL::ConfigError) do
+      OpenSSL::Config.parse(<<__EOC__)
+# comment 1               # comments
+
+#
+ # comment 2
+\t#comment 3
+  [second    ]\t
+[third                    # section not terminated
+__EOC__
+    end
+    assert_equal("error in line 7: missing close square bracket", excn.message)
+  end
+
+  def test_s_load
+    # alias of new
+    c = OpenSSL::Config.load
+    assert_equal("", c.to_s)
+    assert_equal([], c.sections)
+    #
+    file = Tempfile.open("openssl.cnf")
+    file.close
+    c = OpenSSL::Config.load(file.path)
+    assert_equal("[ default ]\n\n", c.to_s)
+    assert_equal(['default'], c.sections)
+  end
+
+  def test_initialize
+    c = OpenSSL::Config.new
+    assert_equal("", c.to_s)
+    assert_equal([], c.sections)
+  end
+
+  def test_initialize_with_empty_file
+    file = Tempfile.open("openssl.cnf")
+    file.close
+    c = OpenSSL::Config.new(file.path)
+    assert_equal("[ default ]\n\n", c.to_s)
+    assert_equal(['default'], c.sections)
+  end
+
+  def test_initialize_with_example_file
+    assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
+  end
+
+  def test_get_value
+    assert_equal('CA_default', @it.get_value('ca', 'default_ca'))
+    assert_equal(nil, @it.get_value('ca', 'no such key'))
+    assert_equal(nil, @it.get_value('no such section', 'no such key'))
+    assert_equal('.', @it.get_value('', 'HOME'))
+    assert_raise(TypeError) do
+      @it.get_value(nil, 'HOME') # not allowed unlike Config#value
+    end
+    # fallback to 'default' ugly...
+    assert_equal('.', @it.get_value('unknown', 'HOME'))
+  end
+
+  def test_get_value_ENV
+    key = ENV.keys.first
+    assert_not_nil(key) # make sure we have at least one ENV var.
+    assert_equal(ENV[key], @it.get_value('ENV', key))
+  end
+
+  def test_value
+    # supress deprecation warnings
+    OpenSSL::TestUtils.silent do
+      assert_equal('CA_default', @it.value('ca', 'default_ca'))
+      assert_equal(nil, @it.value('ca', 'no such key'))
+      assert_equal(nil, @it.value('no such section', 'no such key'))
+      assert_equal('.', @it.value('', 'HOME'))
+      assert_equal('.', @it.value(nil, 'HOME'))
+      assert_equal('.', @it.value('HOME'))
+      # fallback to 'default' ugly...
+      assert_equal('.', @it.value('unknown', 'HOME'))
+    end
+  end
+
+  def test_value_ENV
+    OpenSSL::TestUtils.silent do
+      key = ENV.keys.first
+      assert_not_nil(key) # make sure we have at least one ENV var.
+      assert_equal(ENV[key], @it.value('ENV', key))
+    end
+  end
+
+  def test_aref
+    assert_equal({'HOME' => '.'}, @it['default'])
+    assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default'])
+    assert_equal({}, @it['no_such_section'])
+    assert_equal({}, @it[''])
+  end
+
+  def test_section
+    OpenSSL::TestUtils.silent do
+      assert_equal({'HOME' => '.'}, @it.section('default'))
+      assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default'))
+      assert_equal({}, @it.section('no_such_section'))
+      assert_equal({}, @it.section(''))
+    end
+  end
+
+  def test_sections
+    assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
+    @it['new_section'] = {'foo' => 'bar'}
+    assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
+    @it['new_section'] = {}
+    assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
+  end
+
+  def test_add_value
+    c = OpenSSL::Config.new
+    assert_equal("", c.to_s)
+    # add key
+    c.add_value('default', 'foo', 'bar')
+    assert_equal("[ default ]\nfoo=bar\n\n", c.to_s)
+    # add another key
+    c.add_value('default', 'baz', 'qux')
+    assert_equal('bar', c['default']['foo'])
+    assert_equal('qux', c['default']['baz'])
+    # update the value
+    c.add_value('default', 'baz', 'quxxx')
+    assert_equal('bar', c['default']['foo'])
+    assert_equal('quxxx', c['default']['baz'])
+    # add section and key
+    c.add_value('section', 'foo', 'bar')
+    assert_equal('bar', c['default']['foo'])
+    assert_equal('quxxx', c['default']['baz'])
+    assert_equal('bar', c['section']['foo'])
+  end
+
+  def test_aset
+    @it['foo'] = {'bar' => 'baz'}
+    assert_equal({'bar' => 'baz'}, @it['foo'])
+    @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'}
+    assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
+
+    # OpenSSL::Config is add only for now.
+    @it['foo'] = {'foo' => 'foo'}
+    assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
+    # you cannot override or remove any section and key.
+    @it['foo'] = {}
+    assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
+  end
+
+  def test_each
+    # each returns [section, key, value] array.
+    ary = @it.map { |e| e }.sort { |a, b| a[0] <=> b[0] }
+    assert_equal(4, ary.size)
+    assert_equal('CA_default', ary[0][0])
+    assert_equal('CA_default', ary[1][0])
+    assert_equal(["ca", "default_ca", "CA_default"], ary[2])
+    assert_equal(["default", "HOME", "."], ary[3])
+  end
+
+  def test_to_s
+    c = OpenSSL::Config.parse("[empty]\n")
+    assert_equal("[ default ]\n\n[ empty ]\n\n", c.to_s)
+  end
+
+  def test_inspect
+    assert_match(/#<OpenSSL::Config sections=\[.*\]>/, @it.inspect)
+  end
+
+  def test_freeze
+    c = OpenSSL::Config.new
+    c['foo'] = [['key', 'value']]
+    c.freeze
+
+    # [ruby-core:18377]
+    # RuntimeError for 1.9, TypeError for 1.8
+    assert_raise(TypeError, /frozen/) do
+      c['foo'] = [['key', 'wrong']]
+    end
+  end
+
+  def test_dup
+    assert(!@it.sections.empty?)
+    c = @it.dup
+    assert_equal(@it.sections.sort, c.sections.sort)
+    @it['newsection'] = {'a' => 'b'}
+    assert_not_equal(@it.sections.sort, c.sections.sort)
+  end
+
+  def test_clone
+    assert(!@it.sections.empty?)
+    c = @it.clone
+    assert_equal(@it.sections.sort, c.sections.sort)
+    @it['newsection'] = {'a' => 'b'}
+    assert_not_equal(@it.sections.sort, c.sections.sort)
+  end
+end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]