デコード2
昨日の記事で書いたデコーダをもうちょっと簡単に出来ないものかと思い、ちょっと違うものを書いてみた。
!String methodsFor: 'converting'! urlDecode | inData str | str := ReadWriteStream on: ''. inData := self copyReplaceAll: '+' with: '%20'. inData := (inData tokenize: '%'). ((inData at: 1) ~= '' or: [(inData at: 1) = '']) ifTrue: [ str nextPutAll: (inData at: 1). inData := inData copyFrom: 2 to: inData size. ]. inData do: [:each | | asciiVal | asciiVal := (each at: 1) asUppercase digitValue * 16 + (each at: 2) asUppercase digitValue. asciiVal > 255 ifTrue: [^self]. str nextPut: (Character value: asciiVal). (2 < each size) ifTrue: [str nextPutAll: (each copyFrom: 3 to: each size)]. ]. ^str contents. !
ちょっと簡単になった? けど、遅そうだな・・・ 計測してみる。
#!/usr/bin/env gst | str time | str := '大量のURLエンコード文字列'. time := Time millisecondsToRun: [ str urlDecode. ]. time printNl.
予想通り、めっちゃ遅いorz 昨日のやつの方が約2倍は早い。他に何か良い方法はないかなぁ。
まぁ、なにわともあれデコード出来るようになったので、テスト的にメールフォームCGIなんぞを作ってみる。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>てすとmailフォーム</title> </head> <body> <form action="sendMail.cgi" method="POST" accept-charset="UTF-8"> お名前<br> <input name="name" size="30"><br> メールアドレス<br> <input name="email" size="30"><br> メッセージ<br> <textarea name="message" rows="10" cols="30"></textarea><br> <input type="submit" value="送信"> <input type="reset" value="リセット"> </form> </body> </html>
#!/usr/bin/env gst -Q stdout nextPutAll: 'Content-Type: text/plain; charset=UTF-8';nl;nl; nextPutAll: 'ありがとうございます^^'. PackageLoader fileInPackage: 'NetClients'. ! | inData message client | inData := ((stdin nextAvailable: (Smalltalk getenv: 'CONTENT_LENGTH') asInteger) tokenize: '&') inject: Dictionary new into: [:dic :each | | array | array := (each tokenize: '='). dic at: (array at: 1) put: (array at: 2) urlDecode; yourself ]. message := NetClients.MIME.MimeEntity readFrom: ('From: %1 To: %2 Subject: %3 [%4]さんからメッセージ %5 ' % {inData at: 'email'. 'user@hoge.domain'. 'Message'. inData at: 'name'. inData at: 'message'} ) readStream. client := NetClients.SMTP.SMTPClient connectToHost: 'localhost'. [client sendMessage: message] ensure: [client close]. !
本当はもっとちゃんとエラー処理とかやらなきゃならないけど、まぁ、テストなんで、こんな感じでOK.メールも問題無く送信できた。SMTPライブラリは素のままだと使い勝手が良いとは言えないので、何かラップした方がよさそう。あと、このライブラリをCGIで使う場合、 smalltalk/net/SMTP.st の139行目あたりの aMessage inspect. をコメントアウトしとかないといけない。でないと、inspectの結果がstdoutに出力されてしまう。デバッグ用には良いですけどね。さらに、 smalltalk/kernel/Metaclass.st の181行目と335行目あたりの Transcript nextPutAll: 'Recompiling classes...'; nl. もコメントアウトしとかないと、 PackageLoader fileInPackage: でパッケージをfileinしたときに Recompiling classes... がstdoutに出力される時がある。自分は最初その事に気付かなくて、原因不明のBad headerエラーが出るなぁとか思ったりしてたんすけど、原因はこれだった。^^;