Skip to content

Commit

Permalink
HTTP Archive 1.2 support
Browse files Browse the repository at this point in the history
  • Loading branch information
Ahmad Nassri committed Mar 22, 2015
1 parent 9ad49bf commit 132a010
Show file tree
Hide file tree
Showing 5 changed files with 551 additions and 0 deletions.
191 changes: 191 additions & 0 deletions lib/har.js
@@ -0,0 +1,191 @@
'use strict'

var fs = require('fs')
var path = require('path')
var qs = require('querystring')
var util = require('util')

function Har (request) {
this.request = request
}

Har.prototype.reducer = function (obj, pair) {
// new property ?
if (obj[pair.name] === undefined) {
obj[pair.name] = pair.value
return obj
}

// existing? convert to array
var arr = [
obj[pair.name],
pair.value
]

obj[pair.name] = arr

return obj
}

Har.prototype.prep = function (har) {
var data = util._extend({}, har)

// only process the first entry
if (data.log && data.log.entries) {
data = data.log.entries[0]
}

// construct utility properties
data.queryObj = {}
data.headersObj = {}
data.postData = data.postData ? data.postData : {}
data.postData.jsonObj = false
data.postData.paramsObj = false

// construct query objects
if (data.queryString && data.queryString.length) {
data.queryObj = data.queryString.reduce(this.reducer, {})
}

// construct headers objects
if (data.headers && data.headers.length) {
// loweCase header keys
data.headersObj = data.headers.reduceRight(function (headers, header) {
headers[header.name] = header.value
return headers
}, {})
}

// construct Cookie heade
if (data.cookies && data.cookies.length) {
var cookies = data.cookies.map(function (cookie) {
return cookie.name + '=' + cookie.value
})

if (cookies.length) {
data.headersObj.cookie = cookies.join('; ')
}
}

// prep body
switch (data.postData.mimeType) {
case 'multipart/mixed':
case 'multipart/related':
case 'multipart/form-data':
case 'multipart/alternative':
// reset values
data.postData.mimeType = 'multipart/form-data'
break

case 'application/x-www-form-urlencoded':
if (!data.postData.params) {
data.postData.text = ''
} else {
data.postData.paramsObj = data.postData.params.reduce(this.reducer, {})

// always overwrite
data.postData.text = qs.stringify(data.postData.paramsObj)
}
break

case 'text/json':
case 'text/x-json':
case 'application/json':
case 'application/x-json':
data.postData.mimeType = 'application/json'

if (data.postData.text) {
try {
data.postData.jsonObj = JSON.parse(data.postData.text)
} catch (e) {
this.request.debug(e)

// force back to text/plain
data.postData.mimeType = 'text/plain'
}
}
break
}

return data
}

Har.prototype.options = function (options) {
// skip if no har property defined
if (!options.har) {
return options
}

// clean up and get some utility properties
var req = this.prep(options.har)

// construct new options
if (req.url) {
options.url = req.url
}

if (req.method) {
options.method = req.method
}

if (Object.keys(req.queryObj).length) {
options.qs = req.queryObj
}

if (Object.keys(req.headersObj).length) {
options.headers = req.headersObj
}

switch (req.postData.mimeType) {
case 'application/x-www-form-urlencoded':
options.form = req.postData.paramsObj
break

case 'application/json':
if (req.postData.jsonObj) {
options.body = req.postData.jsonObj
options.json = true
}
break

case 'multipart/form-data':
options.formData = {}

req.postData.params.forEach(function (param) {
var attachement = {}

if (!param.fileName && !param.fileName && !param.contentType) {

This comment has been minimized.

Copy link
@henryju

henryju Jun 22, 2017

Duplicate condition.

options.formData[param.name] = param.value
return
}

// attempt to read from disk!
if (param.fileName && !param.value) {
attachement.value = fs.createReadStream(param.fileName)
} else if (param.value) {
attachement.value = param.value
}

if (param.fileName) {
var base = path.parse(param.fileName).base

attachement.options = {
filename: base.length ? base : 'filename',
contentType: param.contentType ? param.contentType : null
}
}

options.formData[param.name] = attachement
})
break

default:
if (req.postData.text) {
options.body = req.postData.text
}
}

return options
}

exports.Har = Har
8 changes: 8 additions & 0 deletions request.js
Expand Up @@ -22,6 +22,7 @@ var http = require('http')
, cookies = require('./lib/cookies')
, copy = require('./lib/copy')
, getProxyFromURI = require('./lib/getProxyFromURI')
, Har = require('./lib/har').Har
, Auth = require('./lib/auth').Auth
, OAuth = require('./lib/oauth').OAuth
, Multipart = require('./lib/multipart').Multipart
Expand Down Expand Up @@ -244,6 +245,13 @@ function Request (options) {
// call init

var self = this

// start with HAR, then override with additional options
if (options.har) {
self._har = new Har(self)
options = self._har.options(options)
}

stream.Stream.call(self)
var reserved = Object.keys(Request.prototype)
var nonReserved = filterForNonReserved(reserved, options)
Expand Down
158 changes: 158 additions & 0 deletions tests/fixtures/har.json
@@ -0,0 +1,158 @@
{
"application-form-encoded": {
"method": "POST",
"headers": [
{
"name": "content-type",
"value": "application/x-www-form-urlencoded"
}
],
"postData": {
"mimeType": "application/x-www-form-urlencoded",
"params": [
{
"name": "foo",
"value": "bar"
},
{
"name": "hello",
"value": "world"
}
]
}
},

"application-json": {
"method": "POST",
"headers": [
{
"name": "content-type",
"value": "application/json"
}
],
"postData": {
"mimeType": "application/json",
"text": "{\"number\":1,\"string\":\"f\\\"oo\",\"arr\":[1,2,3],\"nested\":{\"a\":\"b\"},\"arr_mix\":[1,\"a\",{\"arr_mix_nested\":{}}]}"
}
},

"cookies": {
"method": "POST",
"cookies": [
{
"name": "foo",
"value": "bar"
},
{
"name": "bar",
"value": "baz"
}
]
},

"custom-method": {
"method": "PROPFIND"
},

"headers": {
"method": "GET",
"headers": [
{
"name": "x-foo",
"value": "Bar"
}
]
},

"multipart-data": {
"method": "POST",
"headers": [
{
"name": "content-type",
"value": "multipart/form-data"
}
],
"postData": {
"mimeType": "multipart/form-data",
"params": [
{
"name": "foo",
"value": "Hello World",
"fileName": "hello.txt",
"contentType": "text/plain"
}
]
}
},

"multipart-file": {
"method": "POST",
"headers": [
{
"name": "content-type",
"value": "multipart/form-data"
}
],
"postData": {
"mimeType": "multipart/form-data",
"params": [
{
"name": "foo",
"fileName": "../tests/unicycle.jpg",
"contentType": "image/jpeg"
}
]
}
},

"multipart-form-data": {
"method": "POST",
"headers": [
{
"name": "content-type",
"value": "multipart/form-data"
}
],
"postData": {
"mimeType": "multipart/form-data",
"params": [
{
"name": "foo",
"value": "bar"
}
]
}
},

"query": {
"method": "GET",
"queryString": [
{
"name": "foo",
"value": "bar"
},
{
"name": "foo",
"value": "baz"
},
{
"name": "baz",
"value": "abc"
}
]
},

"text-plain": {
"method": "POST",
"headers": [
{
"name": "content-type",
"value": "text/plain"
}
],
"postData": {
"mimeType": "text/plain",
"text": "Hello World"
}
}
}

0 comments on commit 132a010

Please sign in to comment.