Mashape/mockbin

View on GitHub
lib/middleware/body-parser.js

Summary

Maintainability
B
4 hrs
Test Coverage
F
32%
const Dicer = require("dicer");
const querystring = require("querystring");
const contentTypeParser = require("content-type");
const util = require("../utils");

const parseContentType = (contentTypeHeader) => {
    if (!contentTypeHeader) {
        return { contentType: null };
    }
    const { type, parameters } = contentTypeParser.parse(contentTypeHeader);
    return {
        contentType: type.replace(/\+$/, ""),
        parameters,
    };
};

module.exports = (req, res, next) => {
    req.bodyChunks = [];

    req.on("data", (chunk) => {
        req.bodyChunks.push(chunk);
    });

    req.on("end", () => {
        req.rawBody = Buffer.concat(req.bodyChunks);
        req.body = req.rawBody.toString("utf8");
        req.bodySize = req.rawBody.length;
        req.jsonBody = null;
        req.formBody = null;
        req.contentType = null;
        req.multiPartSimple = {};

        // parse Content-Type
        const contentTypeHeader = req.headers["content-type"];
        const { contentType, parameters } = parseContentType(contentTypeHeader);

        if (contentType) {
            req.contentType = contentType;
        }

        // create HAR Object
        req.har = util.createHar(req);
        req.simple = util.createSimpleHar(req);

        switch (req.contentType) {
            case "application/json":
                try {
                    req.jsonBody = JSON.parse(req.body);
                } catch (exception) {}

                next();
                break;

            case "application/x-www-form-urlencoded":
                req.formBody = querystring.parse(req.body);

                // update HAR objects
                req.simple.postData.params = req.formBody;
                req.har.log.entries[0].request.postData.params = util.objectToArray(
                    req.formBody,
                );

                next();
                break;

            case "multipart/mixed":
            case "multipart/related":
            case "multipart/form-data":
            case "multipart/alternate": {
                req.multiPartData = [];
                req.multiPartParams = [];

                // parse a file upload
                const dice = new Dicer({
                    boundary: parameters.boundary,
                });

                dice.on("part", (part) => {
                    part.on("data", (data) => {
                        req.multiPartData.push(data.toString("utf8"));
                    });

                    part.on("header", (headers) => {
                        const param = {};

                        if (headers["content-disposition"]) {
                            const disposition = contentTypeParser.parse(
                                headers["content-disposition"][0].replace(
                                    "form-data",
                                    "form-data/text",
                                ) || "form-data/text",
                            );

                            param.name = disposition.parameters.name;

                            if (disposition.parameters.filename) {
                                param.fileName = disposition.parameters.filename;
                            }
                        }

                        if (headers["content-type"]) {
                            const { contentType: partContentType } = parseContentType(
                                headers["content-type"][0] || "application/octet-stream",
                            );

                            param.contentType = partContentType;
                        }

                        req.multiPartParams.push(param);
                    });
                });

                dice.on("finish", () => {
                    // createa a new simple object param
                    req.multiPart = req.multiPartParams.map((param, index) => {
                        // append value to pair
                        param.value = req.multiPartData[index];

                        switch (typeof req.multiPartSimple[param.name]) {
                            case "undefined":
                                req.multiPartSimple[param.name] = param.value;
                                break;

                            // array
                            case "object":
                                req.multiPartSimple[param.name].push(param.value);
                                break;

                            case "string":
                                // this exists? must be an array, make it so
                                req.multiPartSimple[param.name] = [
                                    req.multiPartSimple[param.name],
                                ];
                                req.multiPartSimple[param.name].push(param.value);
                                break;
                        }

                        return param;
                    });

                    // update HAR objects
                    req.simple.postData.params = req.multiPartSimple
                        ? req.multiPartSimple
                        : [];
                    req.har.log.entries[0].request.postData.params = req.multiPart
                        ? req.multiPart
                        : [];

                    next();
                });

                dice.write(req.body);
                break;
            }

            default:
                next();
        }
    });
};