request-parser.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import {IncomingMessage} from 'http';
  2. import {Errorf} from '@e22m4u/js-format';
  3. import {isPromise} from '../utils/index.js';
  4. import {BodyParser} from './body-parser.js';
  5. import {QueryParser} from './query-parser.js';
  6. import {CookieParser} from './cookie-parser.js';
  7. import {DebuggableService} from '../debuggable-service.js';
  8. /**
  9. * Request parser.
  10. */
  11. export class RequestParser extends DebuggableService {
  12. /**
  13. * Parse.
  14. *
  15. * @param {IncomingMessage} req
  16. * @returns {Promise<object>|object}
  17. */
  18. parse(req) {
  19. if (!(req instanceof IncomingMessage))
  20. throw new Errorf(
  21. 'The first argument of RequestParser.parse should be ' +
  22. 'an instance of IncomingMessage, but %v given.',
  23. req,
  24. );
  25. const data = {};
  26. const promises = [];
  27. // парсинг "query" выполняется с проверкой
  28. // значения, так как парсер может вернуть
  29. // Promise, и тогда придется разрывать
  30. // "eventLoop" с помощью "await"
  31. const parsedQuery = this.getService(QueryParser).parse(req);
  32. if (isPromise(parsedQuery)) {
  33. promises.push(parsedQuery.then(v => (data.query = v)));
  34. } else {
  35. data.query = parsedQuery;
  36. }
  37. // аналогично предыдущей операции, разбираем
  38. // данные заголовка "cookie" с проверкой
  39. // значения на Promise, и разрываем
  40. // "eventLoop" при необходимости
  41. const parsedCookie = this.getService(CookieParser).parse(req);
  42. if (isPromise(parsedCookie)) {
  43. promises.push(parsedCookie.then(v => (data.cookie = v)));
  44. } else {
  45. data.cookie = parsedCookie;
  46. }
  47. // аналогично предыдущей операции, разбираем
  48. // тело запроса с проверкой результата
  49. // на наличие Promise
  50. const parsedBody = this.getService(BodyParser).parse(req);
  51. if (isPromise(parsedBody)) {
  52. promises.push(parsedBody.then(v => (data.body = v)));
  53. } else {
  54. data.body = parsedBody;
  55. }
  56. // что бы предотвратить модификацию
  57. // заголовков, возвращаем их копию
  58. data.headers = JSON.parse(JSON.stringify(req.headers));
  59. // если имеются асинхронные операции, то результат
  60. // будет обернут в Promise, в противном случае
  61. // данные возвращаются сразу
  62. return promises.length ? Promise.all(promises).then(() => data) : data;
  63. }
  64. }