Skip to content
This repository has been archived by the owner on Dec 3, 2021. It is now read-only.

Commit

Permalink
fix(lib): handle form-data (adding text for backwards compatibility) (#1
Browse files Browse the repository at this point in the history
)
  • Loading branch information
derevnjuk authored Jul 17, 2020
1 parent 97f98e6 commit 4a03b76
Show file tree
Hide file tree
Showing 17 changed files with 4,673 additions and 407 deletions.
18 changes: 0 additions & 18 deletions .circleci/config.yml

This file was deleted.

23 changes: 23 additions & 0 deletions .github/workflows/auto-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI / Automated testing

on:
pull_request:
branches:
- master

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 13.x, 14.x]
steps:
- uses: actions/checkout@v2
with:
token: ${{ secrets.GPR_TOKEN }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci -q
- run: npm t
49 changes: 49 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Automated deploy

on:
push:
tags:
- 'v*'

jobs:
prepare:
runs-on: ubuntu-latest
outputs:
project_version: ${{ steps.project_version.outputs.value }}
project: ${{ steps.project.outputs.value }}
steps:
- id: project_version
run: echo ::set-output name=value::${GITHUB_REF/refs\/tags\//}
- id: project
run: echo ::set-output name=value::$(echo ${GITHUB_REPOSITORY#*/} | tr A-Z a-z)

deploy:
runs-on: ubuntu-latest
needs: prepare
env:
PROJECT: ${{ needs.prepare.outputs.project }}
VERSION: ${{ needs.prepare.outputs.project_version }}
steps:
- uses: actions/checkout@v2
with:
token: ${{ secrets.GPR_TOKEN }}

- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: 'https://registry.npmjs.org'

- run: npm version --no-git-tag-version "$VERSION"
- run: npm ci -q
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

- uses: actions/setup-node@v1
with:
registry-url: 'https://npm.pkg.github.com'
scope: '@NeuraLegion'

- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.GPR_TOKEN }}
22 changes: 22 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Semantic release

on:
push:
branches:
- master

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
token: ${{ secrets.GPR_TOKEN }}
- uses: actions/setup-node@v1
with:
node-version: 12

- name: Semantic release
run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GPR_TOKEN }}
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ build/Release

# Dependency directories
node_modules
package-lock.json
yarn.lock
jspm_packages

# Optional npm cache directory
Expand Down
35 changes: 35 additions & 0 deletions .releaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"parserOpts": {
"noteKeywords": ["BREAKING CHANGE", "BREAKING CHANGES"]
}
}
],
[
"@semantic-release/release-notes-generator",
{
"writerOpts": {
"commitsSort": ["subject", "scope"]
}
}
],
[
"@semantic-release/npm",
{
"npmPublish": false
}
],
[
"@semantic-release/github",
{
"labels": false,
"releasedLabels": false
}
]
],
"branch": "master",
"ci": true
}
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# capture-har

**THIS REPO HAS BEEN DEPRECATED. THE DEVELOPMENT HAS MOVED TO A NEW REPOSITORY: https://github.com/NeuraLegion/har-recorder**

Fetch requests in HAR format

This module makes a request and captures it as a [HAR](http://www.softwareishard.com/blog/har-12-spec/) object.
Expand All @@ -12,7 +14,7 @@ It can now be also used in stream mode. This means that it will stream data even

```js
// Promise mode
const captureHar = require('capture-har');
const captureHar = require('@neuralegion/capture-har');
captureHar({
url: 'http://www.google.com'
}, { withContent: false })
Expand All @@ -21,7 +23,7 @@ captureHar({
});

// Stream mode
const CaptureHar = require('capture-har').CaptureHar;
const CaptureHar = require('@neuralegion/capture-har').CaptureHar;
const captureHar = new CaptureHar(require('request'));
captureHar.start({ url: 'http://www.google.com' })
.on('data', data => // data event will contain the response body as it is received)
Expand Down
102 changes: 96 additions & 6 deletions lib/buildHar.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const querystring = require('querystring');
const encodingUtil = require('./encoding-util');
const { parseHttpVersion } = require('./parser');

const BASE64_PATTERN = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/

function buildFlattenedNameValueMap (obj) {
if (!obj) {
return [];
Expand Down Expand Up @@ -33,11 +35,99 @@ function buildHarQuery (query) {
return buildFlattenedNameValueMap(querystring.parse(query));
}

function buildHarPostData (body, request) {
return body ? {
mimeType: getMimeType(request),
text: body
} : undefined;
function getMultipartContentType(param) {
if (param && param.contentType) {
return param.contentType
}

if (param.value.startsWith('{') && param.value.endsWith('}')) {
return 'application/json'
}

if (BASE64_PATTERN.test(param.value)) {
return 'application/octet-stream'
}
}

function convertFormDataToText(value, boundary) {
const EOL = '\r\n'

let rawData = value
.reduce((params, item) => {
const multipartContentType = getMultipartContentType(item)

let param = `--${boundary}${EOL}`

param += `Content-Disposition: form-data; name="${item.name}"`

if (multipartContentType) {
param += `${EOL}Content-Type: ${multipartContentType}`
}

param += `${EOL + EOL}`
param += typeof item.value === 'object' ? JSON.stringify(item.value) : item.value

params.push(param)

return params
}, [])
.join(EOL)
rawData += EOL
rawData += `--${boundary}--`
return rawData
}

function convertFormData(name, param, params) {
switch (typeof param) {
case "object":
if (Array.isArray(param)) {
param.forEach((x) => params.push(convertFormData(name, x, params)))
} else if (Buffer.isBuffer(param)) {
params.push({name: name, value: param.toString('utf8')});
} else if (param.options) {
var value = Buffer.isBuffer(param.value) ?
param.value.toString('utf8') :
(param.value || '').toString();

params.push({
name: name,
value: value,
fileName: param.options.filename,
contentType: param.options.contentType || getMimeType(value)
});
}
break;
default:
params.push({
name,
value: (param || '').toString()
});
}
}

function buildHarPostData (request) {
if (request.body) {
return {
mimeType: getMimeType(request),
text: request.body
}
}
if (request.formData) {
var params = [];

Object.keys(request.formData).forEach((name) => {
var value = request.formData[name];
convertFormData(name, value, params);
})
let header = request.getHeader('content-type');
let boundary = header.split(" ")[1]
boundary = boundary.split("=")[1]
return {
mimeType: 'multipart/form-data',
params: params,
text: convertFormDataToText(params, boundary)
}
}
}

function getMimeType (response) {
Expand Down Expand Up @@ -126,7 +216,7 @@ function buildHarRequest (request = {}) {
cookies: buildHarCookies(request.headers && request.headers.cookie && request.headers.cookie.split(';')),
headers: buildHarHeaders(request.req && request.req._headers || request.headers),
queryString: buildHarQuery(request.uri && request.uri.query),
postData: buildHarPostData(request.body, request),
postData: buildHarPostData(request),
headersSize: -1,
bodySize: -1
};
Expand Down
21 changes: 21 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {CoreOptions, OptionsWithUrl, Request, RequestAPI, RequiredUriUrl} from "request";
import {Har} from "har-format";

declare interface HarOptions {
withContent?: boolean;
maxContentLength?: number;
}

declare function captureHar(requestConfig: OptionsWithUrl, harConfig: HarOptions): Har;

declare namespace captureHar {
class CaptureHar {
constructor(request: RequestAPI<Request, CoreOptions, RequiredUriUrl>);

start(requestConfig: OptionsWithUrl, harConfig?: HarOptions, depth?: number): Har;

stop(): Har;
}
}

export = captureHar;
Loading

0 comments on commit 4a03b76

Please sign in to comment.