Skip to content

Commit

Permalink
Adding CR to multipart requests based on multipart content-type header,
Browse files Browse the repository at this point in the history
Closes #74 #118 #29
  • Loading branch information
Rikard Qvarforth authored and Adam Kliment committed Feb 16, 2015
1 parent fe6f186 commit d3e4725
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 4 deletions.
23 changes: 19 additions & 4 deletions src/transaction-runner.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ logger = require './logger'


String::startsWith = (str) ->
return this.slice(0, str.length) is str
return this.slice(0, str.length) is str

class TransactionRunner
constructor: (@configuration) ->
Expand Down Expand Up @@ -113,11 +113,11 @@ class TransactionRunner
# Add length of body if no Content-Length present
# Doing here instead of in configureTransaction, because request body can be edited in before hook

caseInsensitiveMap = {}
caseInsensitiveRequestHeadersMap = {}
for key, value of transaction.request.headers
caseInsensitiveMap[key.toLowerCase()] = key
caseInsensitiveRequestHeadersMap[key.toLowerCase()] = key

if not caseInsensitiveMap['content-length'] and transaction.request['body'] != ''
if not caseInsensitiveRequestHeadersMap['content-length'] and transaction.request['body'] != ''
transaction.request.headers['Content-Length'] = Buffer.byteLength(transaction.request['body'], 'utf8')

requestOptions =
Expand Down Expand Up @@ -209,6 +209,9 @@ class TransactionRunner
return callback()

transport = if transaction.protocol is 'https:' then https else http
if transaction.request['body'] and @isMultipart requestOptions
@replaceLineFeedInBody transaction, requestOptions

try
req = transport.request requestOptions, handleRequest
req.write transaction.request['body'] if transaction.request['body'] != ''
Expand All @@ -217,4 +220,16 @@ class TransactionRunner
configuration.emitter.emit 'test error', error, test if error
return callback()

isMultipart: (requestOptions) =>
caseInsensitiveRequestHeaders = {}
for key, value of requestOptions.headers
caseInsensitiveRequestHeaders[key.toLowerCase()] = value
caseInsensitiveRequestHeaders['content-type']?.indexOf("multipart") > -1

replaceLineFeedInBody: (transaction, requestOptions) =>
transaction.request['body'] = transaction.request['body'].replace(/\n/g, '\r\n')
transaction.request['headers']['Content-Length'] = transaction.request['body'].length
requestOptions.headers = transaction.request['headers']


module.exports = TransactionRunner
116 changes: 116 additions & 0 deletions test/unit/transaction-runner-test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -405,3 +405,119 @@ describe 'TransactionRunner', ()->
runner.executeTransaction transaction, () ->
assert.ok server.isDone()
done()

describe 'executeTransaction(transaction, callback) multipart', () ->
multiPartTransaction = null
notMultiPartTransaction = null
runner = null
beforeEach () ->
runner = new Runner(configuration)
multiPartTransaction =
name: 'Group Machine > Machine > Post Message> Bogus example name'
id: 'POST /machines/message'
host: 'localhost'
port: '3000'
request:
body: '\n--BOUNDARY \ncontent-disposition: form-data; name="mess12"\n\n{"message":"mess1"}\n--BOUNDARY\n\nContent-Disposition: form-data; name="mess2"\n\n{"message":"mess1"}\n--BOUNDARY--'
headers:
'Content-Type': 'multipart/form-data; boundary=BOUNDARY'
'User-Agent': 'Dredd/0.2.1 (Darwin 13.0.0; x64)'
'Content-Length': 180
uri: '/machines/message'
method: 'POST'
expected:
headers:
'content-type': 'text/htm'
body: ''
status: '204'
origin:
resourceGroupName: 'Group Machine'
resourceName: 'Machine'
actionName: 'Post Message'
exampleName: 'Bogus example name'
fullPath: '/machines/message'
protocol: 'http:'

notMultiPartTransaction =
name: 'Group Machine > Machine > Post Message> Bogus example name'
id: 'POST /machines/message'
host: 'localhost'
port: '3000'
request:
body: '\n--BOUNDARY \ncontent-disposition: form-data; name="mess12"\n\n{"message":"mess1"}\n--BOUNDARY\n\nContent-Disposition: form-data; name="mess2"\n\n{"message":"mess1"}\n--BOUNDARY--'
headers:
'Content-Type': 'text/plain'
'User-Agent': 'Dredd/0.2.1 (Darwin 13.0.0; x64)'
'Content-Length': 180
uri: '/machines/message'
method: 'POST'
expected:
headers:
'content-type': 'text/htm'
body: ''
status: '204'
origin:
resourceGroupName: 'Group Machine'
resourceName: 'Machine'
actionName: 'Post Message'
exampleName: 'Bogus example name'
fullPath: '/machines/message'
protocol: 'http:'

describe 'when multipart header in request', () ->

parsedBody = '\r\n--BOUNDARY \r\ncontent-disposition: form-data; name="mess12"\r\n\r\n{"message":"mess1"}\r\n--BOUNDARY\r\n\r\nContent-Disposition: form-data; name="mess2"\r\n\r\n{"message":"mess1"}\r\n--BOUNDARY--'
beforeEach () ->
server = nock('http://localhost:3000').
post('/machines/message').
reply 204
configuration.server = 'http://localhost:3000'

afterEach () ->
nock.cleanAll()

it 'should replace line feed in body', (done) ->
runner.executeTransaction multiPartTransaction, () ->
assert.ok server.isDone()
assert.equal multiPartTransaction['request']['body'], parsedBody, 'Body'
assert.include multiPartTransaction['request']['body'], "\r\n"
done()

describe 'when multipart header in request is with lowercase key', () ->

parsedBody = '\r\n--BOUNDARY \r\ncontent-disposition: form-data; name="mess12"\r\n\r\n{"message":"mess1"}\r\n--BOUNDARY\r\n\r\nContent-Disposition: form-data; name="mess2"\r\n\r\n{"message":"mess1"}\r\n--BOUNDARY--'
beforeEach () ->
server = nock('http://localhost:3000').
post('/machines/message').
reply 204
configuration.server = 'http://localhost:3000'

delete multiPartTransaction['request']['headers']['Content-Type']
multiPartTransaction['request']['headers']['content-type'] = 'multipart/form-data; boundary=BOUNDARY'

afterEach () ->
nock.cleanAll()

it 'should replace line feed in body', (done) ->
runner.executeTransaction multiPartTransaction, () ->
assert.ok server.isDone()
assert.equal multiPartTransaction['request']['body'], parsedBody, 'Body'
assert.include multiPartTransaction['request']['body'], "\r\n"
done()

describe 'when multipart header is not in request', () ->
beforeEach () ->
server = nock('http://localhost:3000').
post('/machines/message').
reply 204
configuration.server = 'http://localhost:3000'

afterEach () ->
nock.cleanAll()

it 'should not include any line-feed in body', (done) ->
runner.executeTransaction notMultiPartTransaction, () ->
assert.ok server.isDone()
assert.notInclude multiPartTransaction['request']['body'], "\r\n"
done()

0 comments on commit d3e4725

Please sign in to comment.