node-xmlrpcでCDATAを含むデータでエラーが出る

hubotnode-xmlrpcを使って、 IRC上からconfluenceにページを作成するものを作ってたのだが、 どうも特定のページを元にページを作成しようとするとエラーがでて失敗してしまう。 調べてみると、どうも生成しようとするページ内にCDATAが含まれていると失敗するっぽい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
xmlrpc = require 'xmlrpc'
async = require 'async'

clientOption =
  host: "host"
  path: "/confluence/rpc/xmlrpc"
  port: 443

space = '~userspace'
userName = 'username'
password = 'password'

client = xmlrpc.createSecureClient clientOption

title = "てすと"
content = '<ac:macro ac:name="code"><ac:plain-text-body><![CDATA[<html>hogehoge</html>]]></ac:plain-text-body></ac:macro>'

async.waterfall [
  (callback) ->
    client.methodCall "confluence2.login", [userName, password], callback
  (token, callback) ->
    page =
      space: space
      parentId: '0'
      title: title
      content: content
    client.methodCall "confluence2.storePage", [token, page], callback
], (err, page) ->
  console.log page

こんな感じのコードを書いて実行すると、Invalid CDATA textというエラーが出てページが作成できない。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ coffee confluence.coffee

/Users/saiten/local/tmp/confl/node_modules/xmlrpc/node_modules/xmlbuilder/lib/XMLFragment.js:150
        throw new Error("Invalid CDATA text: " + value);
              ^
  Error: Invalid CDATA text: <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[<html>hogehoge</html>]]></ac:plain-text-body></ac:macro>
    at XMLFragment.cdata (/Users/saiten/local/tmp/confl/node_modules/xmlrpc/node_modules/xmlbuilder/lib/XMLFragment.js:150:15)
  at XMLFragment.d (/Users/saiten/local/tmp/confl/node_modules/xmlrpc/node_modules/xmlbuilder/lib/XMLFragment.js:355:19)
    at appendString (/Users/saiten/local/tmp/confl/node_modules/xmlrpc/lib/serializer.js:172:23)
  at serializeValue (/Users/saiten/local/tmp/confl/node_modules/xmlrpc/lib/serializer.js:92:11)
    at /Users/saiten/local/tmp/confl/node_modules/xmlrpc/lib/serializer.js:25:5
  at Array.forEach (native)
    at Object.exports.serializeMethodCall (/Users/saiten/local/tmp/confl/node_modules/xmlrpc/lib/serializer.js:24:10)
  at Client.methodCall (/Users/saiten/local/tmp/confl/node_modules/xmlrpc/lib/client.js:100:30)
    at /Users/saiten/local/tmp/confl/test/confluence.coffee:28:5, <js>:38:21
  at fn (/Users/saiten/local/tmp/confl/node_modules/async/lib/async.js:579:34)
    at Object._onImmediate (/Users/saiten/local/tmp/confl/node_modules/async/lib/async.js:495:34)
  at processImmediate [as _immediateCallback] (timers.js:330:15)

どうもCDATAが含まれる文字列なのにCDATAで囲もうとして失敗してるようだったので、 node-xmlrpcのserializer.jsの以下の部分を直したらうまく行った。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@@ -163,14 +163,10 @@ function appendBoolean(value, xml) {
   xml.ele('boolean').txt(value ? 1 : 0)
    }

-var illegalChars = /^(?![^<&]*]]>[^<&]*)[^<&]*$/
 function appendString(value, xml) {
    if (value.length === 0) {
     xml.ele('string')
    }
-  else if (!illegalChars.test(value)) {
-    xml.ele('string').d(value)
-  }
   else {
        xml.ele('string').txt(value)
   }

動くけどこの修正で良いのか微妙なところ。

Comments