submit.js
3.46 KB
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*jshint -W100*/
'use strict';
var urlParser = require('url');
var typeOf = require('type-of');
var each = require('foreach');
var cutil = require('./util');
module.exports = function (encoding, client, cheerio) {
/**
* form要素からの送信をエミュレート
*
* @param param 疑似設定するフォーム送信パラメータ
* @param callback リクエスト完了時のコールバック関数(err, response, body(buffer))
*/
var emulateSubmit = function (elem, param, callback) {
if (param === 'sync' || typeOf(param) === 'function') {
callback = param;
param = {};
}
param = param || {};
var doc = cutil.documentInfo(elem);
var $form = null;
// form要素でなければエラー
try {
if (elem.length === 0) {
throw new Error('no elements');
}
// 複数ある場合は先頭のフォームのみ
$form = elem.eq(0);
if (! $form.is('form')) {
throw new Error('element is not form');
}
} catch (e) {
return client.error(e.message, {
param: { uri: doc.url },
callback: callback
});
}
// methodとURL確定
var method = ($form.attr('method') || 'GET').toUpperCase();
var url = urlParser.resolve(doc.url, $form.attr('action') || '');
// フォーム送信パラメータ作成
// 1. デフォルトパラメータ($form.field())を取得した後に
// 2. 引数で指定したパラメータ(param)で上書き
var formParam = {};
each([ $form.field(), param ], function (fp) {
each(fp, function (val, name) {
var fparam = cutil.paramFilter(val);
var fvalue = (typeOf(fparam) === 'array') ? fparam : [ fparam ];
// 空パラメータでもname=のみで送信するための仕込み
if (fvalue.length === 0) {
fvalue.push('');
}
formParam[name] = fvalue;
});
});
// 各種エンコーディングに対応したURLエンコードをする必要があるのでパラメータ文字列を自力で作成
var formParamArray = [];
// accept-charsetは先頭で指定されているものを使用
var enc = ($form.attr('accept-charset') || doc.encoding).split(/[\s,]+/)[0];
each(formParam, function (val, name) {
formParamArray.push(val.map(function (vv) {
var escName = encoding.escape(enc, name);
var escVal = encoding.escape(enc, vv);
if (method === 'POST') {
// application/x-www-form-urlencodedでは半角スペースは%20ではなく+にする
escName = escName.replace(/%20/g, '+');
escVal = escVal.replace(/%20/g, '+');
}
return escName + '=' + escVal;
}).join('&'));
});
var formParamStr = formParamArray.join('&');
// GETの場合はURLに繋げてパラメータを空にする(そうしないと上手く動かないケースがたまにあった)
if (method === 'GET') {
var join = (url.indexOf('?') === -1) ? '?' : '&';
if (formParamStr.length > 0) {
url += join + formParamStr;
}
formParamStr = {};
}
return client.run(method, url, formParamStr, null, callback);
};
/**
* 非同期フォーム送信
*/
cheerio.prototype.submit = function (param, callback) {
return emulateSubmit(this, param, callback);
};
/**
* 同期フォーム送信
*/
cheerio.prototype.submitSync = function (param) {
return emulateSubmit(this, param, 'sync');
};
};