har.js (4787B)
1 'use strict' 2 3 var fs = require('fs') 4 var qs = require('querystring') 5 var validate = require('har-validator') 6 var extend = require('extend') 7 8 function Har (request) { 9 this.request = request 10 } 11 12 Har.prototype.reducer = function (obj, pair) { 13 // new property ? 14 if (obj[pair.name] === undefined) { 15 obj[pair.name] = pair.value 16 return obj 17 } 18 19 // existing? convert to array 20 var arr = [ 21 obj[pair.name], 22 pair.value 23 ] 24 25 obj[pair.name] = arr 26 27 return obj 28 } 29 30 Har.prototype.prep = function (data) { 31 // construct utility properties 32 data.queryObj = {} 33 data.headersObj = {} 34 data.postData.jsonObj = false 35 data.postData.paramsObj = false 36 37 // construct query objects 38 if (data.queryString && data.queryString.length) { 39 data.queryObj = data.queryString.reduce(this.reducer, {}) 40 } 41 42 // construct headers objects 43 if (data.headers && data.headers.length) { 44 // loweCase header keys 45 data.headersObj = data.headers.reduceRight(function (headers, header) { 46 headers[header.name] = header.value 47 return headers 48 }, {}) 49 } 50 51 // construct Cookie header 52 if (data.cookies && data.cookies.length) { 53 var cookies = data.cookies.map(function (cookie) { 54 return cookie.name + '=' + cookie.value 55 }) 56 57 if (cookies.length) { 58 data.headersObj.cookie = cookies.join('; ') 59 } 60 } 61 62 // prep body 63 function some (arr) { 64 return arr.some(function (type) { 65 return data.postData.mimeType.indexOf(type) === 0 66 }) 67 } 68 69 if (some([ 70 'multipart/mixed', 71 'multipart/related', 72 'multipart/form-data', 73 'multipart/alternative'])) { 74 // reset values 75 data.postData.mimeType = 'multipart/form-data' 76 } else if (some([ 77 'application/x-www-form-urlencoded'])) { 78 if (!data.postData.params) { 79 data.postData.text = '' 80 } else { 81 data.postData.paramsObj = data.postData.params.reduce(this.reducer, {}) 82 83 // always overwrite 84 data.postData.text = qs.stringify(data.postData.paramsObj) 85 } 86 } else if (some([ 87 'text/json', 88 'text/x-json', 89 'application/json', 90 'application/x-json'])) { 91 data.postData.mimeType = 'application/json' 92 93 if (data.postData.text) { 94 try { 95 data.postData.jsonObj = JSON.parse(data.postData.text) 96 } catch (e) { 97 this.request.debug(e) 98 99 // force back to text/plain 100 data.postData.mimeType = 'text/plain' 101 } 102 } 103 } 104 105 return data 106 } 107 108 Har.prototype.options = function (options) { 109 // skip if no har property defined 110 if (!options.har) { 111 return options 112 } 113 114 var har = {} 115 extend(har, options.har) 116 117 // only process the first entry 118 if (har.log && har.log.entries) { 119 har = har.log.entries[0] 120 } 121 122 // add optional properties to make validation successful 123 har.url = har.url || options.url || options.uri || options.baseUrl || '/' 124 har.httpVersion = har.httpVersion || 'HTTP/1.1' 125 har.queryString = har.queryString || [] 126 har.headers = har.headers || [] 127 har.cookies = har.cookies || [] 128 har.postData = har.postData || {} 129 har.postData.mimeType = har.postData.mimeType || 'application/octet-stream' 130 131 har.bodySize = 0 132 har.headersSize = 0 133 har.postData.size = 0 134 135 if (!validate.request(har)) { 136 return options 137 } 138 139 // clean up and get some utility properties 140 var req = this.prep(har) 141 142 // construct new options 143 if (req.url) { 144 options.url = req.url 145 } 146 147 if (req.method) { 148 options.method = req.method 149 } 150 151 if (Object.keys(req.queryObj).length) { 152 options.qs = req.queryObj 153 } 154 155 if (Object.keys(req.headersObj).length) { 156 options.headers = req.headersObj 157 } 158 159 function test (type) { 160 return req.postData.mimeType.indexOf(type) === 0 161 } 162 if (test('application/x-www-form-urlencoded')) { 163 options.form = req.postData.paramsObj 164 } else if (test('application/json')) { 165 if (req.postData.jsonObj) { 166 options.body = req.postData.jsonObj 167 options.json = true 168 } 169 } else if (test('multipart/form-data')) { 170 options.formData = {} 171 172 req.postData.params.forEach(function (param) { 173 var attachment = {} 174 175 if (!param.fileName && !param.contentType) { 176 options.formData[param.name] = param.value 177 return 178 } 179 180 // attempt to read from disk! 181 if (param.fileName && !param.value) { 182 attachment.value = fs.createReadStream(param.fileName) 183 } else if (param.value) { 184 attachment.value = param.value 185 } 186 187 if (param.fileName) { 188 attachment.options = { 189 filename: param.fileName, 190 contentType: param.contentType ? param.contentType : null 191 } 192 } 193 194 options.formData[param.name] = attachment 195 }) 196 } else { 197 if (req.postData.text) { 198 options.body = req.postData.text 199 } 200 } 201 202 return options 203 } 204 205 exports.Har = Har