UNPKG

@sap/odata-v4

Version:

OData V4.0 server library

163 lines (135 loc) 4.97 kB
'use strict'; const HeaderReader = require('./HeaderReader'); const LineReader = require('./LineReader'); const Reader = require('./Reader'); /** * States * @enum {number} * @readonly */ const STATES = { READ_REQUEST_LINE: 0, READ_REQUEST_LINE_RETURN: 1, RUN_HEADER_READER: 2, RUN_HEADER_READER_RETURN: 3, RUN_READER: 4, RUN_READER_RETURN: 5, FINISHED: 6 }; /** * Events * @enum {string} * @readonly */ const EVENTS = { START: 'request.start', REQUEST_LINE: 'request.requestline', HEADERS: 'request.headers', BODY_START: 'request.body.start', BODY_END: 'request.body.end', END: 'request.end' }; const BODY_PREFIX = 'body'; /** * * Reading a application/http request from the cache. The request must be in the format described by mime type application/http * and the cache must start with the request line * * @extends Reader */ class ApplicationHttpReader extends Reader { /** * Factory for automatic creation depending on content-type * @returns {ApplicationHttpReader} a new instance of this class */ static createInstance() { return new ApplicationHttpReader(); } /** * Constructor */ constructor() { super(); this._state = STATES.READ_REQUEST_LINE; this._headerInfos = null; this._headerReader = null; this._bodyReader = null; /** * Request line (e.g. POST /service/$batch HTTP/1.1) without leading/trailing CRLFs * @private */ this._requestLine = null; this._stopPattern = null; } /** * Set the stop pattern. E.g. when mime type application/http is used inside a multipart request * * @param {string} stopPattern */ setStopPattern(stopPattern) { this._stopPattern = stopPattern; } /** * Read data from cache until the boundary is read. If the cache is empty and more data is required, * this is signaled and readCache is called again. The state is preserved. * * @param {ContentDeserializer} reader * @returns {boolean} * this: this reader needs more data and caller should call this method again with more data in cache * false: this reader is finished caller should pop this reader from stack * null: new sub reader is on stack, call this method again after the sub reader is finished */ readCache(reader) { let needMoreData = false; while (needMoreData === false && this._state !== STATES.FINISHED) { switch (this._state) { case STATES.READ_REQUEST_LINE: this.emit(EVENTS.START); this.lineReader = new LineReader(); reader.pushReader(this.lineReader); this._state = STATES.READ_REQUEST_LINE_RETURN; needMoreData = null; break; case STATES.READ_REQUEST_LINE_RETURN: this._requestLine = this.lineReader.getLine(); this.emit(EVENTS.REQUEST_LINE, this._requestLine); this._state = STATES.RUN_HEADER_READER; break; case STATES.RUN_HEADER_READER: this._headerReader = new HeaderReader().setEmitter(this._emitter); reader.pushReader(this._headerReader); this._state = STATES.RUN_HEADER_READER_RETURN; needMoreData = null; break; case STATES.RUN_HEADER_READER_RETURN: this._headerInfos = this._headerReader.getHeaderInfos(); this._headerInfosRaw = this._headerReader.getHeaderInfosRaw(); this.emit(EVENTS.HEADERS, this._headerInfosRaw, this._headerInfos); this._state = STATES.RUN_READER; break; case STATES.RUN_READER: this._bodyReader = reader.getNextReader(this._headerInfos).setEmitter(this._emitter, BODY_PREFIX); if (this._stopPattern) { this._bodyReader.setStopPattern(this._stopPattern); } reader.pushReader(this._bodyReader); this.emit(EVENTS.BODY_START); this._state = STATES.RUN_READER_RETURN; needMoreData = null; break; case STATES.RUN_READER_RETURN: this.emit(EVENTS.BODY_END); this.emit(EVENTS.END); this._state = STATES.FINISHED; needMoreData = false; break; default: break; } } return needMoreData; } } ApplicationHttpReader.EVENTS = EVENTS; ApplicationHttpReader.BODY_PREFIX = BODY_PREFIX; module.exports = ApplicationHttpReader;