초기화 함수 init(7)

김대웅·2021년 7월 16일
0

express 분석

목록 보기
11/14

trustProxyDefaultSymbol

  • set함수에서 "trust proxy fn"함수 값을 설정할때, trustProxyDefaultSymbol의 값을 false로 설정하고 defaultConfiguration함수에서 trustProxyDefaultSymbol의 값을 true로 변경하는 부분이 있다.
app.set = function set(setting, val) {

  if (arguments.length === 1) {
    // app.get(setting)
    return this.settings[setting];
  }

  debug('set "%s" to %o', setting, val);

  // trigger matched settings
  switch (setting) {
    case "etag":
      this.set("etag fn", compileETag(val));
      break;
    case "query parser":
      this.set("query parser fn", compileQueryParser(val));
      break;
    case "trust proxy":
      this.set("trust proxy fn", compileTrust(val));

      // trust proxy inherit back-compat
      Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
        configurable: true,
        value: false, <- trustProxyDefaultSymbol의 값을 false로 설정한다.
      });

      break;
  }

  return this;
};
app.defaultConfiguration = function defaultConfiguration() {
  var env = process.env.NODE_ENV || "development";

  // default settings
  this.enable("x-powered-by");
  this.set("etag", "weak");
  this.set("env", env);
  this.set("query parser", "extended");
  this.set("subdomain offset", 2);
  this.set("trust proxy", false); <- trustProxyDefaultSymbol를 false로 설정

  // trust proxy inherit back-compat
  Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
    configurable: true,
    value: true, <- trustProxyDefaultSymbol를 true로 설정
  });

  debug("booting in %s mode", env);

  this.on("mount", function onmount(parent) {
    // inherit trust proxy
    if (
      this.settings[trustProxyDefaultSymbol] === true &&
      typeof parent.settings["trust proxy fn"] === "function"
    ) {
      delete this.settings["trust proxy"];
      delete this.settings["trust proxy fn"];
    }

    // inherit protos
    setPrototypeOf(this.request, parent.request);
    setPrototypeOf(this.response, parent.response);
    setPrototypeOf(this.engines, parent.engines);
    setPrototypeOf(this.settings, parent.settings);
  });

  // setup locals
  this.locals = Object.create(null);

  // top-most app is mounted at /
  this.mountpath = "/";

  // default locals
  this.locals.settings = this.settings;

  // default configuration
  this.set("view", View);
  this.set("views", resolve("views"));
  this.set("jsonp callback name", "callback");

  if (env === "production") {
    this.enable("view cache");
  }

  Object.defineProperty(this, "router", {
    get: function () {
      throw new Error(
        "'app.router' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app."
      );
    },
  });
};
  • trust proxy의 설정 변경 여부를 저장하기위해 이렇게 코드를 작성한게 아닐까 추측하였다.
  • 그 이외에 trustProxyDefaultSymbol이 사용되는 경우는 defaultConfiguration의 mount이벤트 설정뿐이다.
 this.on("mount", function onmount(parent) {
    // inherit trust proxy
    if (
      this.settings[trustProxyDefaultSymbol] === true &&
      typeof parent.settings["trust proxy fn"] === "function"
    ) {
      delete this.settings["trust proxy"];
      delete this.settings["trust proxy fn"];
    }

    // inherit protos
    setPrototypeOf(this.request, parent.request);
    setPrototypeOf(this.response, parent.response);
    setPrototypeOf(this.engines, parent.engines);
    setPrototypeOf(this.settings, parent.settings);
  });
  • 내가 추측한것처럼 trust proxy의 변경여부를 설정하기위해 만든 코드인것 같다.

코드 분석

express/lib/application.js

app.defaultConfiguration = function defaultConfiguration() {
  var env = process.env.NODE_ENV || "development";

  // default settings
  this.enable("x-powered-by");
  this.set("etag", "weak");
  this.set("env", env);
  this.set("query parser", "extended");
  this.set("subdomain offset", 2);
  this.set("trust proxy", false);

  // trust proxy inherit back-compat
  Object.defineProperty(this.settings, trustProxyDefaultSymbol, {
    configurable: true,
    value: true,
  });

  debug("booting in %s mode", env);

  /**
   * mount 이벤트
   *
   * const express = require("express");
   * const app = express();
   * const admin = express();
   * app.use("/admin", admin); <- 마운트 이벤트 발생
   */

  this.on("mount", function onmount(parent) {
    // inherit trust proxy
    if (
      this.settings[trustProxyDefaultSymbol] === true &&
      typeof parent.settings["trust proxy fn"] === "function"
    ) {
      delete this.settings["trust proxy"];
      delete this.settings["trust proxy fn"];
    }
    /**
     * trust proxy가 default로 설정되어 있는 경우
     * 해당 설정을 지운다.
     */

    // inherit protos
    /**
     * 부모의 프로퍼티를 자식의 프로퍼티의 프로토타입으로 설정한다.
     */
    setPrototypeOf(this.request, parent.request);
    setPrototypeOf(this.response, parent.response);
    setPrototypeOf(this.engines, parent.engines);
    setPrototypeOf(this.settings, parent.settings);
    /**
     * 개체와 프로토타입에 동일한 이름의 프로퍼티가 설정되어 있는 경우
     * 자식 프로퍼티를 우선한다.
     * 
     * setPrototypeOf를 이용하여 부모의 프로퍼티를 자식의 프로퍼티의 프로토타입으로 설정한 이유는
     * 자식의 프로퍼티에 설정된 값이 있다면 자식의 값을 우선적으로 사용할수 있도록 하기위한것이 아닐까 추측
     */
  });

  // setup locals
  this.locals = Object.create(null);
  /**
   * hasOwnProperty등의 기본 메서드조차 없는 개체를 생성한다.
   */

  // top-most app is mounted at /
  this.mountpath = "/";
  /**
   * 위의 설정을 통해 마운트 이벤트가 정확하게 어떤 이벤트인지 감을 잡을 수 있는것 같다.
   */

  // default locals
  this.locals.settings = this.settings;

  // default configuration
  this.set("view", View);
  this.set("views", resolve("views"));
  this.set("jsonp callback name", "callback");

  if (env === "production") {
    this.enable("view cache");
  }

  Object.defineProperty(this, "router", {
    get: function () {
      throw new Error(
        "'app.router' is deprecated!\nPlease see the 3.x to 4.x migration guide for details on how to update your app."
      );
    },
  });
};

setPrototypeOf/index.js

"use strict";
/* eslint no-proto: 0 */
module.exports =
  Object.setPrototypeOf ||
  ({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties);
/**
 * Object.setPrototypeOf가 (null || undefined)등이 아닌경우 Object.setPrototypeOf를 사용한다.
 * Object.setPrototypeOf가 (null || undefined)인 경우 __proto__프로퍼티가 개체의 프로토타입을 변경할수 있는지 여부를 통하여 결정한다.
 */

/**
 * { __proto__: [] } 의 프로토타입
 * 1. 개체 리터럴로 선언하였으므로 프로토타입은 Object이다.
 * 2. __proto__프로퍼티를 배열 리터럴로 선언하였으므로 __proto__는 배열이다.
 * 3. 만약 __proto__의 값 변경을 통해 프로토타입을 변경할 수 있다면, { __proto__: [] }의 프로토타입은 배열이 될것이다.
 * 4. 만약 __proto__의 값을 변경하더라도 프로토타입을 변경할 수 없다면, { __proto__: [] }의 프로토타입은 개체가 될것이다.
 */

/**
 * __proto__프로퍼티 변경을 통한 프로토타입 변경 가능여부를 확인해야하는 이유
 *
 * 1. __proto__는 es6이전에 표준이 아니었다.
 * 2. es6를 통한 __proto__프로퍼티의 표준화 작업을 통해, __proto__프로퍼티를 통한 프로토타입 변경을 할 수 없게되었다.
 *
 * https://2ality.com/2015/09/proto-es6.html 참고
 * https://levelup.gitconnected.com/the-mysterious-javascript-objects-proto-property-67b7c6b3140c 참고
 */

/**
 * __proto__를 통하여 프로토타입 자체를 변경한다.
 */
function setProtoOf(obj, proto) {
  obj.__proto__ = proto;
  return obj;
}

/**
 * __proto__를 통한 프로토타입 변경이 힘든경우
 * proto의 프로퍼티중 obj에 없는 프로퍼티만 복사한다.
 */
function mixinProperties(obj, proto) {
  for (var prop in proto) {
    if (!Object.prototype.hasOwnProperty.call(obj, prop)) {
      obj[prop] = proto[prop];
    }
  }
  return obj;
}
profile
42seoul cadet

0개의 댓글