<commit_before>import HttpMethods from '../http-methods';
import FetchStates from '../fetch-states';

/**
 * Create a browser http layer. A request will return a function that can be used to abort the request. An argument can be passed
 * to the function. It will be dispatched to the store. If action is a function, then the argument will be passed to the function
 * creator.
 * Options Supported :
 *  beforeRequest
 *  bodyParse
 *  afterResponse
 *  responseParse
 *
 * @returns {{get: get, put: put, post: post, head: head, delete: delete, patch: patch}}
 */
export function createDefaultHttpLayer() {
  function doHttpRequest(stateDisptacher, method, request) {
    let requestCompleted = false;
    let requestCancelled = false;
    function loadHandler() {
      requestCompleted = true;
      let afterResponse  = request.options && request.options.afterResponse; //(response) => response
      let responseParse  = request.options && request.options.responseParse; //(response) => any
      const xhr          = this;

      let response    = {
        data              : xhr.response,
        status            : xhr.status,
        statusText        : xhr.statusText,
        getResponseHeader : xhr.getResponseHeader,
        request           : request,
        method            : method,
        ok: (xhr.status >= 200 && xhr.status <= 299)
      };
      let responseOk  = response.ok;

      let newResponse = afterResponse && afterResponse(response);

      if (newResponse)
        response = newResponse;

      response = responseParse ? responseParse(response) : response;

      if (responseOk)
        stateDisptacher(FetchStates.FETCH_COMPLETED, response);
      else
        stateDisptacher(FetchStates.FETCH_ERROR, response);
    };

    let beforeRequest  = request.options && request.options.beforeRequest; //(request)  => void
    let bodyParse      = request.options && request.options.bodyParse;     //(body)     => body
    let xhr            = new XMLHttpRequest();

    xhr.addEventListener('load',loadHandler);
    xhr.open(method, request.fullPath, true);
    for (let hKey in request.headers)
      xhr.setRequestHeader(hKey, request.headers[hKey]);

    if (beforeRequest)
      beforeRequest(request);

    stateDisptacher(FetchStates.FETCH_STARTED);
    xhr.send(bodyParse ? bodyParse(request.body) : request.body);

    return (payload) => {
      if (!requestCompleted && !requestCancelled) {
        requestCancelled = true;
        xhr.removeEventListener('load', loadHandler);
        xhr.abort();
        stateDisptacher(FetchStates.FETCH_CANCELLED, payload);
      }
    };
  }

  return {
    get : function (stateDisptacher, request) {
      return doHttpRequest(stateDisptacher, HttpMethods.GET, request);
    },
    put : function (stateDisptacher, request) {
      return doHttpRequest(stateDisptacher, HttpMethods.PUT, request);
    },
    post : function (stateDisptacher, request) {<commit_msg>Add request mutation protection<commit_after>import HttpMethods from '../http-methods';
import FetchStates from '../fetch-states';

/**
 * Create a browser http layer. A request will return a function that can be used to abort the request. An argument can be passed
 * to the function. It will be dispatched to the store. If action is a function, then the argument will be passed to the function
 * creator.
 * Options Supported :
 *  beforeRequest
 *  bodyParse
 *  afterResponse
 *  responseParse
 *
 * @returns {{get: get, put: put, post: post, head: head, delete: delete, patch: patch}}
 */
export function createDefaultHttpLayer() {
  function doHttpRequest(stateDisptacher, method, request) {
    let requestCompleted = false;
    let requestCancelled = false;
    function loadHandler() {
      requestCompleted = true;
      let afterResponse  = request.options && request.options.afterResponse; //(response) => response
      let responseParse  = request.options && request.options.responseParse; //(response) => any
      const xhr          = this;

      let response    = {
        data              : xhr.response,
        status            : xhr.status,
        statusText        : xhr.statusText,
        getResponseHeader : xhr.getResponseHeader,
        request           : request,
        method            : method,
        ok: (xhr.status >= 200 && xhr.status <= 299)
      };
      let responseOk  = response.ok;
      let newResponse = afterResponse && afterResponse(response);

      if (newResponse)
        response = newResponse;

      response = responseParse ? responseParse(response) : response;

      if (responseOk)
        stateDisptacher(FetchStates.FETCH_COMPLETED, response);
      else
        stateDisptacher(FetchStates.FETCH_ERROR, response);
    };

    let beforeRequest  = request.options && request.options.beforeRequest; //(request)  => void
    let bodyParse      = request.options && request.options.bodyParse;     //(body)     => body
    let xhr            = new XMLHttpRequest();

    xhr.addEventListener('load',loadHandler);
    xhr.open(method, request.fullPath, true);
    for (let hKey in request.headers)
      xhr.setRequestHeader(hKey, request.headers[hKey]);

    if (beforeRequest)
      beforeRequest(Object.assign({},request));

    stateDisptacher(FetchStates.FETCH_STARTED);
    xhr.send(bodyParse ? bodyParse(request.body) : request.body);

    return (payload) => {
      if (!requestCompleted && !requestCancelled) {
        requestCancelled = true;
        xhr.removeEventListener('load', loadHandler);
        xhr.abort();
        stateDisptacher(FetchStates.FETCH_CANCELLED, payload);
      }
    };
  }

  return {
    get : function (stateDisptacher, request) {
      return doHttpRequest(stateDisptacher, HttpMethods.GET, request);
    },
    put : function (stateDisptacher, request) {
      return doHttpRequest(stateDisptacher, HttpMethods.PUT, request);
    },
    post : function (stateDisptacher, request) {
{'fraction_non_alphanumeric': 0.10334960444369634, 'fraction_numerical': 0.0020198619760983, 'mean_word_length': 2.838501291989664, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2730690', 'n_tokens_mistral': 1657, 'n_tokens_neox': 1614, 'n_words': 435}