« 2007年08月 | メイン | 2008年01月 »

2007年12月27日

[Ruby][Rails] HTTPレスポンスのヘッダ折りたたみ。

こんにちわ。ばたっちです。

net/http使ってHTTPのレスポンスの処理をしていたら、ヘッダのパースでエラーになってるっぽい。


Net::HTTPBadResponse: wrong header line format
    /usr/lib/ruby/1.8/net/http.rb:2034:in `each_response_header'
    /usr/lib/ruby/1.8/net/http.rb:2008:in `read_new'

net/http.rbがHTTPヘッダの折りたたみ表記に対応してないみたいね。


Content-Type: text/html;
              charset=UTF-8

こういうの。確かRFC的には問題なかったと思うのだけど。(間違ってたらすみません)

というわけで以下のように修正。
/usr/lib/ruby/1.8/net/http.rbを直接置き換えてるんだけど、Railsプロジェクト内で上書きさせる方法ってないのかなぁ。(lib/以下に置いてみたけどダメでした)


--- http.rb.orig        2006-07-26 22:27:18.000000000 +0900
+++ http.rb     2007-11-22 12:58:28.000000000 +0900
@@ -2027,12 +2027,20 @@
       end
 
       def each_response_header(sock)
+        pm = ["", ""]
         while true
           line = sock.readuntil("\n", true).sub(/\s+\z/, '')
           break if line.empty?
-          m = /\A([^:]+):\s*/.match(line) or
-              raise HTTPBadResponse, 'wrong header line format'
-          yield m[1], m.post_match
+          m = /\A([^:]+):\s*/.match(line)
+          if m.nil?
+            pm[1] += line
+            next
+          end
+          yield pm[0], pm[1]
+          pm = [m[1], m.post_match]
         end
       end
     end

いちおうちゃんと動いています。(無保証)


追記:environment.rbの最後でrequireしとけばいいみたい。


lib/http_fix.rb
----
module Net   #:nodoc:
  class HTTPResponse
    class << HTTPResponse
      def each_response_header(sock)
        pm = ["", ""]
        while true
          line = sock.readuntil("\n", true).sub(/\s+\z/, '')
          break if line.empty?
          m = /\A([^:]+):\s*/.match(line)
          if m.nil?
            pm[1] += line
            next
          end
          yield pm[0], pm[1]
          pm = [m[1], m.post_match]
        end
      end
    end
  end   # HTTPResponse
end   # module Net

ってファイル作って、config/environment.rbの最後に、以下の行を追加すると。。φ(.. )


require 'http_fix.rb

2007年12月19日

[Rails] SymbolとStringで悩む。

こんにちわ。ばたっちです。

Rails って Symbol と String(文字列)の区別がなく使えるのかと思いきや、ActiveRecordのオブジェクトなどで record[:name]でも record["name"]でも参照できるのは、ActiveRecordクラスでラップしてるからのようで。

Symbolで参照できたり、文字列じゃないといけなかったり変だなーと思ってたら、ActiveRecordで SQLによる検索に connection.select_all(sql)を使ってたからでした。。orz

Rails は全体的に Symbolで統一しようとしている雰囲気なので、ここはなるべく Symbolで参照したいところ。

select_all(sql)の結果は単なるハッシュの配列ですが、find_by_sql(sql)を使うとActiveRecordオブジェクトの配列になります。


class Name < ActiveRecord::Base
end

※connection.select_all の結果はハッシュの配列。
Name.connection.select_all("SELECT * FROM names LIMIT 1")
=> [{"name"=>"名前1", "created_at"=>"2007-12-19 12:00:00"}]

※find_by_sql の結果はActiveRecordの配列。
Name.find_by_sql("SELECT * FROM search_logs LIMIT 1")
=> [#<Name:0x99999999 @attributes={"name"=>"名前1", "created_at"=>"2007-12-19 12:00:00"}>]

※find_by_sql で任意の結果も取れる。@errorsがあるけど参照は問題なさそう。
Name.find_by_sql("SELECT name, substring(created_at, 1, 10) day FROM names LIMIT 1")
=> [#<Name:0x99999999 @attributes={"day"=>"2007-12-19", "name"=>"名前1"},
           @errors=#<ActiveRecord::Errors:0x99999999 @base=#<Name:0x99999999 ...>, @errors={}>>]

※find の結果はActiveRecord。
Name.find(:first)
=> #<Name:0x99999999 @attributes={"name"=>"名前1", "created_at"=>"2007-12-19 12:00:00"}>

find_by_sqlで任意のカラムの結果が取れるとは知らなかった。

@errorsがあるけど、ちゃんと参照はできます。


result[:name]
=> "名前1"

result["name"]
=> "名前1"

@errorsが気持ち悪かったら connection.select_all の結果ハッシュのキーをSymbol変換するかなぁ。


def to_symhash(hash)
 result = {}
 hash.each_key {|k| result[k.to_sym] = hash[k] }
 result
end

results = Name.connection.select_all("SELECT * FROM names LIMIT 1")
results.collect{|r| to_symhash(r) }
=>[{:created_at=>"2007-12-19 12:00:00", :name=>"名前1"}]

2007年12月17日

[Trac][SVN] Trac+SVNな環境構築。

こんにちわ。ばたっちです。

いまさらですが Trac+SVNな環境を構築することがあったので覚書。

うわさには聞いていたけど、やたらいろんなものを入れなきゃいけないのですね。。

ちなみにパッケージの依存関係とか面倒なので、ここは硬派に(?)ソースからコンパイルで。

今回インストールしたものは以下のとおり。

  • httpd-2.2.6
  • swig-1.3.33
  • neon-0.25.5
  • subversion-1.4.5
  • Python-2.5.1
  • mod_python-3.3.1
  • sqlite-3.5.3
  • pysqlite-2.4.0
  • Genshi-0.4.4
  • clearsilver-0.10.4
  • trac-0.10.4-ja-1

これだけ入れて、最後にやっと Tracのインストール。。

インストールは以下のように /optに入れるので、適宜読み替えて下さい。


/opt/
 apache22/
 clearsilver/
 neon/
 python25/
 sqlite3/
 svn14/
 swig/
 svnroot/
 tracroot/

では、行きましょう♪


まずは、Subversionの環境構築からです。

[Apache]

wget http://ftp.kddilabs.jp/infosystems/apache/httpd/httpd-2.2.6.tar.bz2
tar jxvf httpd-2.2.6.tar.bz2
cd httpd-2.2.6/
./configure --prefix=/opt/apache22 \
      --enable-modules="so rewrite dav" \
      --enable-proxy --enable-proxy-ajp
make
sudo make install

※apacheアカウント作っとく。
chown -R apache.apache /opt/apache22/

[Python]

wget http://www.python.org/ftp/python/2.5.1/Python-2.5.1.tar.bz2
tar jxvf Python-2.5.1.tar.bz2
cd Python-2.5.1/
./configure --prefix=/opt/python25
make
sudo make install

[SWIG] (SubversionとPythonの連携に使うらしい)

wget http://jaist.dl.sourceforge.net/sourceforge/swig/swig-1.3.33.tar.gz
tar zxvf swig-1.3.33.tar.gz
cd swig-1.3.33/
./configure --prefix=/opt/swig \
      --with-python=/opt/python25/bin/python \
      --without-tcl
make
sudo make install

[neon] (SubversionでURIスキームを使う。0.25.5必須)

wget http://www.webdav.org/neon/neon-0.25.5.tar.gz
tar xvzf neon-0.25.5.tar.gz
cd neon-0.25.5/
./configure --prefix=/opt/local/neon
make
sudo make install

[Subversion]

tar jxvf subversion-1.4.5.tar.bz2
cd subversion-1.4.5/
env PYTHON=/opt/python25/bin/python \
./configure --prefix=/opt/svn14 \
      --with-apxs=/opt/apache22/bin/apxs \
      --with-apr=/opt/apache22/bin/apr-1-config \
      --with-apr-util=/opt/apache22/bin/apu-1-config \
      --enable-swig-bindings=python \
      --with-swig=/opt/swig/bin/swig \
      --with-neon=/opt/neon \
      --disable-static

※Makefileの設定が足りないので手で追加。
vi Makefile
----
-SVN_APR_LIBS = /opt/local/apache22/lib/libapr-0.la -lm -lcrypt
+SVN_APR_LIBS = /opt/local/apache22/lib/libapr-0.la -lm -lcrypt -lgssapi `krb5-config --libs` `xml2-config --libs`
-SVN_APR_INCLUDES = -I/opt/local/apache22/include
+SVN_APR_INCLUDES = -I/opt/local/apache22/include `krb5-config --cflags` `xml2-config --cflags`
----

make
sudo make install
make swig-py
make check-swig-py
sudo make install-swig-py

※Python連携のモジュールへのリンクを作成
cd /opt/python25/lib/python2.5/site-packages
sudo ln -s /opt/svn14/lib/svn-python .
sudo ln -s /opt/svn14/lib/svn-python/* .


ここまでインストールしたら、ひとまず Subversionの環境設定を行います。

まずは、リポジトリの作成。/opt/svnroot に置くようにしました。
リポジトリ作成後に定番のディレクトリを作成します。

svnadmin create /opt/svnroot/test
svn mkdir file:///opt/svnroot/test/trunk \
     file:///opt/svnroot/test/tags \
     file:///opt/svnroot/test/branches \
     -m "make trunk, tags, branches"

できたら、Apacheのモジュール設定。

デフォルトでは conf/extra/ ディレクトリ以下に各モジュール用の設定ファイルを置いて、conf/httpd.conf から読み込むようになっているようです。

既存の conf/extra/ を conf/extra-all/ にし、conf/extra/ 以下に必要なモジュールのみリンクを張るようにしてみました。この辺はお好みで。


conf/httpd.conf
----
-User daemon
-Group daemon
+User apache
+Group apache

+Include conf/extra/*.conf ※ファイルの末尾辺りに。
----

conf/extra/ の構成を変更して、Subversionの設定ファイルを追加する。


mv extra extra-all
mkdir extra

vi conf/extra-all/httpd-svn.conf
----
# cat /opt/apache22/conf/extra/httpd-svn.conf
# Subversion Repository

#LoadModule dav_svn_module modules/mod_dav_svn.so
#LoadModule authz_svn_module modules/mod_authz_svn.so

<Location /svn>
  DAV svn
  SVNParentPath /opt/svnroot

  AuthType Basic
  AuthName "Subversion Authentication Realm"
  AuthUserFile /opt/svnroot/.htpasswd
  AuthGroupFile /opt/svnroot/.htgroup

  # Limit write permission to list of valid users.
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require group svn_commiters
  </LimitExcept>

  <Limit GET PROPFIND OPTIONS REPORT>
    Require group svn_commiters
    Require group svn_readers
  </Limit>
</Location>
----

cd extra/
ln -s ../extra-all/httpd-default.conf .
ln -s ../extra-all/httpd-dav.conf .
ln -s ../extra-all/httpd-svn.conf .

リポジトリにアクセス制限用のファイルを作成します。


cd /opt/svnroot/

/opt/apache22/bin/htpasswd -c /opt/svnroot/.htpasswd user1 ※新規
/opt/apache22/bin/htpasswd /opt/svnroot/.htpasswd user2 ※追加

vi .htgroup
----
svn_commiters: user1
svn_readers: user1 user2
----

※Apacheから書き込みできるようにオーナーを変更
chown -R apache.apache test/

設定が完了したら、Apacheの起動確認です。

/opt/apache22/bin/apachectl を /etc/init.d にコピーするなりして、自動起動の設定などを行います。
(今回は自動起動にしていません。)


cd /etc/init.d/
ln -s /opt/apache22/bin/apachectl apache22

※起動
/etc/init.d/apache22 configtest
/etc/init.d/apache22 start

問題なく起動できたら、http://xxx.xxx.xxx.xxx/svn/test/ へアクセスしてリポジトリが見えたら成功です♪


続いて、Tracの環境構築。ここからが長い。。

必要なものをひたすらインストールしていきます。

[mod_python]

wget http://ftp.riken.jp/net/apache/httpd/modpython/mod_python-3.3.1.tgz
tar zxvf mod_python-3.3.1.tgz
cd mod_python-3.3.1/
./configure --with-apxs=/opt/apache22/bin/apxs \
      --with-python=/opt/python25/bin/python
make
sudo make install

[SQLite3]

※今回はデフォルトでDBはSQLite3に。PostgreSQLでもできるらしい。MySQLはまだお試し版の模様。
wget http://www.sqlite.org/sqlite-3.5.3.tar.gz
tar zxvf sqlite-3.5.3.tar.gz
cd sqlite-3.5.3/
./configure --prefix=/opt/sqlite3 --enable-threadsafe --disable-tcl
make
sudo make install

[pysqlite]

wget http://initd.org/pub/software/pysqlite/releases/2.4/2.4.0/pysqlite-2.4.0.tar.gz
tar zxvf pysqlite-2.4.0.tar.gz
cd pysqlite-2.4.0/

※参照するSQLiteのパスなどを設定
vi setup.cfg
----
 [build_ext]
 define=
 include_dirs=/opt/sqlite3/include
 library_dirs=/opt/sqlite3/lib
+ rpath=/opt/sqlite3/lib ※これ追加
 libraries=sqlite3
----

/opt/python25/bin/python setup.py build

※sqlite用のextensionが、libsqlite3.soを参照できるか確認
ldd build/lib.linux-i686-2.5/pysqlite2/_sqlite.so
    libsqlite3.so.0 => /opt/sqlite3/lib/libsqlite3.so.0 (0x008e4000)
    libpthread.so.0 => /lib/tls/libpthread.so.0 (0x00775000)
    libc.so.6 => /lib/tls/libc.so.6 (0x00b0a000)
    /lib/ld-linux.so.2 (0x00489000)

sudo /opt/python25/bin/python setup.py install

※正常に動作するか確認
/opt/python25/bin/python
>>> from pysqlite2.test import test
>>> test()

[clearsilver]

wget http://www.clearsilver.net/downloads/clearsilver-0.10.4.tar.gz
tar zxvf clearsilver-0.10.4.tar.gz
cd clearsilver-0.10.4/
./configure --prefix=/opt/clearsilver \
      --with-apache=/opt/apache22 \
      --with-python=/opt/python25/bin/python
make
sudo make install

[Genshi]

wget http://ftp.edgewall.com/pub/genshi/Genshi-0.4.4.tar.bz2
tar jxvf Genshi-0.4.4.tar.bz2
cd Genshi-0.4.4/
sudo /opt/python25/bin/python setup.py install

[Trac] ※やっと!

wget http://www.i-act.co.jp/project/products/downloads/trac-0.10.4-ja-1.zip
unzip trac-0.10.4-ja-1.zip
sudo /opt/python25/bin/python setup.py install

ちなみに、pysqlite-2.4.0を使う場合に不具合があるようなので、修正しておきましょう。
(see. http://trac.edgewall.org/changeset/6223)


vi /opt/python25/lib/python2.5/site-packages/trac/db/sqlite_backend.py
----
         raise TracError('Database already exists at %s' % path)
       os.makedirs(os.path.split(path)[0])
+     if isinstance(path, unicode): # needed with 2.4.0
+       path = path.encode('utf-8')
     cnx = sqlite.connect(path, timeout=int(params.get('timeout', 10000)))
     cursor = cnx.cursor()
- - -
       self._active_cursors = weakref.WeakKeyDictionary()
       timeout = int(params.get('timeout', 10.0))
+       if isinstance(path, unicode): # needed with 2.4.0
+         path = path.encode('utf-8')
       cnx = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES,
                  check_same_thread=sqlite_version < 30301,
----


では、これから Tracの環境設定をしていきます。

まずは、リポジトリの作成。/opt/tracroot に作成することにします。


/opt/python25/bin/trac-admin /opt/tracroot/test initenv

※以下の質問に答えていく。
Project Name [My Project]> test
Database connection string [sqlite:db/trac.db]>
Repository type [svn]>
Path to repository [/path/to/repos]> /opt/svnroot/test
Templates directory [/opt/python25/share/trac/templates]>

※リポジトリの文字コード設定を変更しておく。今回は UTF-8
vi /opt/tracroot/test/conf/trac.ini
----
-default_charset = iso-8859-15
+default_charset = utf-8
----

Trac のテスト用サーバを起動して、ブラウザで表示できれば成功です♪


/opt/python25/bin/tracd --port=8000 /opt/tracroot/test

※http://xxx.xxx.xxx.xxx:8000/test/ へアクセス


Trac 単体で動いたら Apache経由の設定を行います。


cd /opt/apache22/conf/

※mod_pythonの設定ファイル作成
vi extra-all/httpd-python.conf
----
LoadModule python_module modules/mod_python.so
----

※Tracの設定ファイル作成
vi extra-all/httpd-trac.conf
----
<Location /trac>
  SetHandler mod_python
  PythonDebug On
  PythonHandler trac.web.modpython_frontend
  PythonOption TracEnvParentDir /opt/tracroot
  PythonOption TracUriRoot /trac
</Location>

<LocationMatch "/trac/.*">
  AuthType Basic
  AuthName "trac"
  AuthUserFile "/opt/tracroot/.htpasswd"
  Require valid-user
</LocationMatch>
----

cd extra/
ln -s ../extra-all/httpd-python.conf .
ln -s ../extra-all/httpd-trac.conf .

Apache から Trac のリポジトリにアクセスできるようにします。


※オーナーを変更
chwon -R apache.apache /opt/tracroot/test/

※アクセス制限のファイル作成
/opt/apache22/bin/htpasswd -c /opt/tracroot/.htpasswd user1

設定ができたら Apacheを再起動します。


/etc/init.d/apache22 configtest
/etc/init.d/apache22 restart

ブラウザで http://xxx.xxx.xxx.xxx/trac/test/ を開いて、Tracの画面が表示できたら成功です♪

Subversion のリポジトリも表示できることを確認しましょう。


以上。お疲れ様でした。A^^;


追記:neon追加