Best JavaScript code snippet using cypress
HTTPRequestProcessor.js
Source:HTTPRequestProcessor.js
1'use strict';2// Including native modules.3const filesystem = require('fs');4const queryString = require('querystring');5// Including Lala's modules.6const RequestProcessor = require('../RequestProcessor');7const UploadedFile = require('../../../Types/UploadedFile');8const HelperRepository = require('../../../Helpers/HelperRepository');9const {10 InvalidArgumentException11} = require('../../../Exceptions');12/**13 * @typedef {RequestProcessorConfiguration} HTTPRequestProcessorConfiguration An object containing all the properties supported by this class.14 *15 * @property {boolean} [allowMethodOverride=false] If set to "true" request method can be defined setting a proper parameter as part of the request.16 * @property {string} [methodOverrideParamName="_method"] The name of the GET/POST parameter that contains the name of the method that will be used in method override (if enabled).17 */18/**19 * Allows to handle client requests processing data and parameters sent over the HTTP protocol.20 */21class HTTPRequestProcessor extends RequestProcessor {22 /**23 * Extract the eTags contained in a given header.24 *25 * @param {string} headerValue A string representing the header contents.26 *27 * @returns {string[]} An array of strings containing the eTags found.28 *29 * @protected30 */31 static _extractETags(headerValue){32 const extractedETags = [];33 // Extract the eTags from the given header contents.34 const eTags = headerValue.split(','), length = eTags.length;35 // Clean up every eTag.36 for ( let i = 0 ; i < length ; i++ ){37 // Remove trailing spaces.38 eTags[i] = eTags[i].trim();39 if ( eTags[i][0] === 'W' && eTags[i][1] === '/' ){40 // Remove the "W/" prefix (indicating that this is a "weak" eTag).41 eTags[i] = eTags[i].substr(2);42 }43 // Remove quotes.44 eTags[i] = eTags[i].substr(1, eTags[i].length - 2);45 extractedETags.push(eTags[i]);46 }47 return extractedETags;48 }49 /**50 * Returns all the properties supported by this class and their default values.51 *52 * @returns {HTTPRequestProcessorConfiguration} An object containing as key the property name and as value its default value.53 *54 * @override55 */56 static getDefaultConfiguration(){57 const baseConfiguration = RequestProcessor.getDefaultConfiguration();58 baseConfiguration.allowMethodOverride = false;59 baseConfiguration.methodOverrideParamName = '_method';60 return baseConfiguration;61 }62 /**63 * Adds the GET parameters extracted and parsed from the query string.64 *65 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.66 *67 * @protected68 */69 _addQueryParameters(request){70 // Processing GET parameters.71 request.query = request._queryStartIndex === -1 ? Object.create(null) : queryString.parse(request.url.substr(request._queryStartIndex + 1));72 }73 /**74 * Adds user credentials found by processing the request URL and the HTTP headers.75 *76 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.77 *78 * @protected79 */80 _addCredentials(request){81 request.credentials = request.authMethod = null;82 if ( request.headers.authorization !== '' && typeof request.headers.authorization === 'string' ){83 // Separate credentials from the authentication method.84 const components = request.headers.authorization.split(' ', 2);85 if ( components.length === 2 ){86 request.authMethod = components[0].toLowerCase();87 if ( request.authMethod === 'basic' ){88 // Decode user credentials used in basic HTTP authentication mechanism.89 const credentials = Buffer.from(components[1], 'base64').toString().split(':');90 if ( credentials.length === 2 ){91 request.credentials = {92 username: credentials[0],93 password: credentials[1]94 };95 }96 }97 }98 }99 }100 /**101 * Adds the client provided language codes to the request object given.102 *103 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.104 *105 * @protected106 */107 _addAcceptedLanguages(request){108 request.languages = Object.create(null);109 request.preferredLanguage = request.preferredLanguageScore = null;110 if ( request.headers['accept-language'] !== '' && typeof request.headers['accept-language'] === 'string' ){111 const blocks = request.headers['accept-language'].split(','), length = blocks.length;112 for ( let i = 0 ; i < length ; i++ ){113 // Split the language code and its score.114 const block = blocks[i].split(';');115 const languageCode = block[0].trim();116 if ( block.length === 1 ){117 // No score found, current language is the default one, set score to 1 (the maximum value allowed).118 request.languages[languageCode] = 1;119 if ( request.preferredLanguage === null ){120 request.preferredLanguage = languageCode;121 request.preferredLanguageScore = 1;122 }123 }else if ( block[1].indexOf('q=') === 0 ){124 // Process priority value defined for current language.125 const priority = parseFloat(block[1].substr(2));126 if ( !isNaN(priority) && priority <= 1 ){127 request.languages[languageCode] = priority;128 if ( request.preferredLanguage === null ){129 request.preferredLanguage = languageCode;130 request.preferredLanguageScore = priority;131 }132 }133 }134 }135 }136 }137 /**138 * Extract segments from request URL's path and then add them to the request object given.139 *140 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.141 *142 * @protected143 */144 _addURLSegments(request){145 if ( request._queryStartIndex === -1 ){146 request.segments = request.url.substr(1).split('/');147 }else{148 request.segments = request.url.substr(0, request._queryStartIndex).split('/');149 }150 }151 /**152 * Applies method override, if enabled, setting current request according to client provided overriding parameter or header.153 *154 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.155 *156 * @protected157 */158 _processMethodOverride(request){159 request.originalMethod = request.method;160 request.methodOverrideParamName = null;161 request.methodOverridden = false;162 if ( this._allowMethodOverride === true ){163 // Method override enabled, save the name of the parameter that should contains the method name making it available across processors.164 request.methodOverrideParamName = this._methodOverrideParamName;165 if ( request.query[this._methodOverrideParamName] !== '' && typeof request.query[this._methodOverrideParamName] === 'string' ){166 // New method name found in a GET parameter.167 request.method = request.query[this._methodOverrideParamName].toUpperCase();168 request.methodOverridden = true;169 }else if ( request.headers['x-http-method-override'] !== '' && typeof request.headers['x-http-method-override'] === 'string' ){170 // New method name found from the "X-Http-Method-Override" HTTP header.171 request.method = request.headers['x-http-method-override'].toUpperCase();172 request.methodOverridden = true;173 }174 }175 }176 /**177 * Parses the content of the "Range" header involved in HTTP range request (used, for instance, in video streaming).178 *179 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.180 *181 * @protected182 */183 _addRange(request){184 request.ranges = [];185 if ( request.headers.range !== '' && typeof request.headers.range === 'string' && request.headers.range.indexOf('bytes=') === 0 ){186 // Extract the header content without the "bytes=" indicating the measurement unit, note that "bytes" is the only supported unit.187 const ranges = request.headers.range.substr(6).split(','), length = ranges.length;188 // Process each requested range.189 for ( let i = 0 ; i < length ; i++ ){190 // Clean up the range syntax.191 ranges[i] = ranges[i].trim();192 const index = ranges[i].indexOf('-');193 if ( index >= 0 ){194 let rangeStart = null, rangeEnd = null, suffixLength = null;195 if ( index === 0 ){196 // This value indicated the number of bytes at the end of the file to return.197 suffixLength = parseInt(ranges[i].substr(1));198 }else{199 // Extract the number of bytes the returned slice should start from.200 rangeStart = parseInt(ranges[i].substr(0, index));201 // If the "-" is not at the end of the string extract the end index as well.202 rangeEnd = index === ( ranges[i].length - 1 ) ? null : parseInt(ranges[i].substr(index + 1));203 }204 request.ranges.push({205 rangeStart: rangeStart,206 rangeEnd: rangeEnd,207 suffixLength: suffixLength208 });209 }210 }211 }212 }213 /**214 * Extracts all the pieces of information from the conditional HTTP headers and the add the conditionals parameters to the request object.215 *216 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.217 *218 * @protected219 */220 _addConditionals(request){221 request.conditionals = {222 matchAnyETag: false,223 matchETags: [],224 modifiedSince: null,225 mismatchAnyETag: false,226 mismatchETags: [],227 unmodifiedSince: null,228 vary: [],229 varyAny: false230 };231 if ( request.headers['if-match'] !== '' && typeof request.headers['if-match'] === 'string' ){232 if ( request.headers['if-match'] === '*' ){233 request.conditionals.matchAnyETag = true;234 }else{235 // Extract the list of eTags.236 request.conditionals.matchETags = HTTPRequestProcessor._extractETags(request.headers['if-match']);237 }238 }239 if ( request.headers['if-modified-since'] !== '' && typeof request.headers['if-modified-since'] === 'string' ){240 const timestamp = Date.parse(request.headers['if-modified-since']);241 if ( !isNaN(timestamp) ){242 request.conditionals.modifiedSince = new Date(timestamp);243 }244 }245 if ( request.headers['if-none-match'] !== '' && typeof request.headers['if-none-match'] === 'string' ){246 if ( request.headers['if-none-match'] === '*' ){247 request.conditionals.mismatchAnyETag = true;248 }else{249 // Extract the list of eTags.250 request.conditionals.mismatchETags = HTTPRequestProcessor._extractETags(request.headers['if-none-match']);251 }252 }253 if ( request.headers['if-unmodified-since'] !== '' && typeof request.headers['if-unmodified-since'] === 'string' ){254 const timestamp = Date.parse(request.headers['if-unmodified-since']);255 if ( !isNaN(timestamp) ){256 request.conditionals.unmodifiedSince = new Date(timestamp);257 }258 }259 if ( request.headers['vary'] !== '' && typeof request.headers['vary'] === 'string' ){260 if ( request.headers['vary'] === '*' ){261 request.conditionals.varyAny = true;262 }else{263 // Extract the list of HTTP headers.264 const headers = request.headers['vary'].split(','), length = headers.length;265 // Clean up and normalize each header of the list.266 for ( let i = 0 ; i < length ; i++ ){267 request.conditionals.vary.push(headers[i].trim().toLowerCase());268 }269 }270 }271 }272 /**273 * Extracts the MIME types accepted and then declared by the client side as part of the "Accept" HTTP header.274 *275 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.276 *277 * @protected278 */279 _addAccept(request){280 request.accept = Object.create(null);281 if ( request.headers.accept !== '' && typeof request.headers.accept === 'string' ){282 // Split the MIME type list into an array of strings.283 const mimes = request.headers.accept.split(','), length = mimes.length;284 for ( let i = 0 ; i < length ; i++ ){285 // Clean up current MIME type.286 mimes[i] = mimes[i].trim();287 // Extract the preference score associated to the MIME type.288 const index = mimes[i].indexOf(';');289 let mime, score;290 if ( index === -1 ){291 // No score associated, use 1.292 mime = mimes[i];293 score = 1;294 }else{295 // Extract and cast the score associated, if not valid, use 1 instead.296 mime = mimes[i].substr(0, index);297 score = parseFloat(mimes[i].substr(index));298 if ( isNaN(score) ){299 score = 1;300 }301 }302 if ( mime !== '' ){303 request.accept[mime] = score;304 }305 }306 }307 }308 /**309 * The class constructor.310 *311 * @param {?HTTPRequestProcessorConfiguration} [configuration=null] An object containing the values for class properties.312 */313 constructor(configuration = null){314 super(configuration);315 /**316 * @type {boolean} [_allowMethodOverride=false] If set to "true" request method can be defined setting a proper parameter as part of the request.317 *318 * @protected319 */320 this._allowMethodOverride = false;321 /**322 * @type {string} [_methodOverrideParamName="_method"] The name of the GET/POST parameter that contains the name of the method that will be used in method override (if enabled).323 *324 * @protected325 */326 this._methodOverrideParamName = '_method';327 if ( configuration !== null && typeof configuration === 'object' ){328 // Setup internal properties.329 this.configure(configuration);330 }331 }332 /**333 * Configures internal properties based on the configuration object given, this method is chainable.334 *335 * @param {HTTPRequestProcessorConfiguration} configuration An object containing the values for class properties.336 *337 * @returns {HTTPRequestProcessor}338 *339 * @throws {InvalidArgumentException} If an invalid configuration object is given.340 *341 * @override342 */343 configure(configuration){344 super.configure(configuration);345 if ( configuration.hasOwnProperty('allowMethodOverride') && typeof configuration.allowMethodOverride === 'boolean' ){346 this._allowMethodOverride = configuration.allowMethodOverride;347 }348 if ( configuration.hasOwnProperty('methodOverrideParamName') && configuration.methodOverrideParamName !== '' && typeof configuration.methodOverrideParamName === 'string' ){349 this._methodOverrideParamName = configuration.methodOverrideParamName;350 }351 return this;352 }353 /**354 * Adds basic properties to a given HTTP request object, for instance GET parameters, user credentials and user languages.355 *356 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.357 * @param {module:http.ServerResponse} response An instance of the built-in class "ServerResponse" representing the response that will be sent back to the client.358 *359 * @returns {Promise<void>}360 *361 * @async362 */363 async process(request, response){364 await super.process(request, response);365 request.user = request.authenticator = request.userSession = request.cookies = request.preflightRequestMethod = null;366 // Marks those properties that will be used in request body processing.367 request.rawBody = undefined;368 request.params = Object.create(null);369 request.secure = request.connection.hasOwnProperty('encrypted');370 request.ignoreConditionalsHeaders = request.isPreflightRequest = false;371 if ( request.method === 'OPTIONS' && typeof request.headers.origin === 'string' && request.headers.origin !== '' ){372 if ( request.headers['access-control-request-method'] !== '' && typeof request.headers['access-control-request-method'] === 'string' ){373 request.isPreflightRequest = true;374 request.preflightRequestMethod = request.headers['access-control-request-method'];375 }376 }377 request.doNotTrack = request.headers['dnt'] === '1';378 this._addQueryParameters(request);379 // Apply method override (if enabled).380 this._processMethodOverride(request);381 this._addCredentials(request);382 this._addAcceptedLanguages(request);383 this._addURLSegments(request);384 this._addRange(request);385 this._addConditionals(request);386 this._addAccept(request);387 // Add helper functions.388 HelperRepository.inject(request, 'com.lala.server.processor.HTTPRequestProcessor.request', {389 context: {390 request: request,391 response: response392 }393 });394 HelperRepository.inject(response, 'com.lala.server.processor.HTTPRequestProcessor.response', {395 context: {396 request: request,397 response: response398 }399 });400 }401 /**402 * Destroys all temporary data that is not more required to exist.403 *404 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.405 *406 * @return {Promise<void>}407 *408 * @protected409 */410 async killRequest(request){411 if ( request.hasOwnProperty('files') && request.files !== null && typeof request.files === 'object' ){412 setImmediate(async () => {413 const processes = [];414 // Remove all the uploaded files from their temporary location.415 for ( const name in request.files ){416 if ( request.files[name] instanceof UploadedFile && !request.files[name].moved() ){417 // Remove the file only if it has not been moved to a permanent location.418 processes.push(filesystem.promises.unlink(request.files[name].getPath()));419 }420 }421 await Promise.all(processes);422 });423 }424 }425}...
CORSOptions.js
Source:CORSOptions.js
1'use strict';2// Including Lala's modules.3const {4 InvalidArgumentException5} = require('../../Exceptions');6/**7 * @callback allowOriginCallback The callback that allows to set the allowed origin dynamically.8 *9 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.10 * @param {module:http.ServerResponse} response An instance of the built-in class "ServerResponse" representing the response that will be sent back to the client.11 *12 * @returns {?string} A string containing the allowed origin or null if any origin should be allowed.13 */14/**15 * Allows to configure the Cross-Origin Resource Sharing (CORS) mechanism on a route, router or server.16 */17class CORSOptions {18 /**19 * Returns the origin to declare to the client as the allowed one.20 *21 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.22 * @param {module:http.ServerResponse} response An instance of the built-in class "ServerResponse" representing the response that will be sent back to the client.23 *24 * @returns {?string} A string containing the origin to declare, if any origin should be allowed will be returned null.25 *26 * @protected27 */28 _getComputedOrigin(request, response){29 let origin = this._allowOrigin;30 if ( typeof this._allowOriginCallback === 'function' ){31 // A callback has been defined, generate the origin dynamically.32 origin = this._allowOriginCallback(request, response);33 }34 return origin;35 }36 /**37 * Checks if a request is valid according to defined CORS settings.38 *39 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.40 * @param {string} origin The origin where the request comes from.41 *42 * @returns {boolean} If the request is valid will be returned "true".43 *44 * @protected45 */46 _validateRequest(request, origin){47 let valid = false;48 // Check if the given origin is accepted.49 if ( origin === '*' || request.headers.origin === origin ){50 const requestMethod = request.headers['access-control-request-method'];51 // Check if the method of the request the client is intended to do is accepted.52 if ( this._allowMethods === null || this._allowMethods.indexOf(requestMethod) >= 0 ){53 if ( this._allowHeaders === null ){54 // Any HTTP header is accepted.55 valid = true;56 }else{57 // Check if every declared HTTP header is accepted.58 const requestHeaders = request.headers['access-control-request-headers'].split(',');59 const length = requestHeaders.length;60 let found = true, i = 0;61 while ( i < length && found ){62 if ( this._allowHeaders.indexOf(requestHeaders[i].trim().toLowerCase()) === -1 ){63 found = false;64 }65 i++;66 }67 valid = found;68 }69 }70 }71 return valid;72 }73 /**74 * The class constructor.75 */76 constructor() {77 /**78 * @type {?string} [_allowOrigin] A string containing the origin URL where requests are allowed from, if null, any URL will be accepted.79 *80 * @protected81 */82 this._allowOrigin = null;83 /**84 * @type {?allowOriginCallback} [_allowOriginCallback] A callback function to invoke in order to get the origin URL dynamically.85 *86 * @protected87 */88 this._allowOriginCallback = null;89 /**90 * @type {?string[]} [_exposeHeaders=[]] An array of strings containing all the HTTP headers that can be exposed as part of the response, if null, any header will be exposed.91 *92 * @protected93 */94 this._exposeHeaders = [];95 /**96 * @type {number} [_maxAge=0] An integer number greater than zero representing how long CORS directives should be cached for on the client side, if zero it will be ignored.97 *98 * @protected99 */100 this._maxAge = 0;101 /**102 * @type {boolean} [_allowCredentials=false] If set to "true" credentials (cookies, authorization headers or TLS client certificates) can be exposed to front-end.103 *104 * @protected105 */106 this._allowCredentials = false;107 /**108 * @type {?string[]} [_allowMethods] An array of strings containing the allowed HTTP methods, if null, any method is allowed.109 *110 * @protected111 */112 this._allowMethods = null;113 /**114 * @type {?string[]} [_allowHeaders] An array of strings containing the allowed HTTP headers, if null, any header is allowed.115 *116 * @protected117 */118 this._allowHeaders = null;119 /**120 * @type {boolean} [_strict=false] If set to "true" incoming requests will be actively validated according to defined settings, if invalid, they will be blocked.121 *122 * @protected123 */124 this._strict = false;125 }126 /**127 * Sets the origin the requests are allowed to come from, this method is chainable.128 *129 * @param {?string} allowOrigin A string containing the origin or null if any origin is accepted.130 *131 * @returns {CORSOptions}132 *133 * @throws {InvalidArgumentException} If an invalid origin is given.134 */135 setAllowOrigin(allowOrigin){136 if ( allowOrigin !== null && ( allowOrigin === '' || typeof allowOrigin !== 'string' ) ){137 throw new InvalidArgumentException('Invalid allowed origin.', 1);138 }139 this._allowOrigin = allowOrigin;140 return this;141 }142 /**143 * Return the origin the requests are allowed to come from that has been defined.144 *145 * @returns {?string} A string containing the origin or null if any origin is accepted.146 */147 getAllowOrigin(){148 return this._allowOrigin;149 }150 /**151 * Sets a callback function that will be invoked in order to determinate the allowed origin for a given request, this method is chainable.152 *153 * @param {?allowOriginCallback} allowOriginCallback A callback function to invoke or null if the allowed origin should be static.154 *155 * @returns {CORSOptions}156 *157 * @throws {InvalidArgumentException} If an invalid callback function is given.158 */159 setAllowOriginCallback(allowOriginCallback){160 if ( allowOriginCallback !== null && typeof allowOriginCallback !== 'function' ){161 throw new InvalidArgumentException('Invalid callback function.', 1);162 }163 this._allowOriginCallback = allowOriginCallback;164 return this;165 }166 /**167 * Returns the callback function that has been defined in order to determinate the allowed origin dynamically.168 *169 * @returns {?allowOriginCallback} The callback function or null if none has been defined.170 */171 getAllowOriginCallback(){172 return this._allowOriginCallback;173 }174 /**175 * Sets the HTTP headers that can be exposed as part of the response, this method is chainable.176 *177 * @param {?string[]} exposeHeaders An array of strings containing the headers, if set to null, any header will be exposed.178 *179 * @returns {CORSOptions}180 *181 * @throws {InvalidArgumentException} If an invalid array of headers is given.182 */183 setExposeHeaders(exposeHeaders){184 if ( exposeHeaders !== null || !Array.isArray(exposeHeaders) ){185 throw new InvalidArgumentException('Invalid exposed headers list.', 1);186 }187 if ( exposeHeaders === null ){188 this._exposeHeaders = null;189 }else{190 // Normalize the given headers converting the into the lower case form.191 this._exposeHeaders = [];192 const length = exposeHeaders.length;193 for ( let i = 0 ; i < length ; i++ ){194 this._exposeHeaders.push(exposeHeaders[i].toLowerCase());195 }196 }197 return this;198 }199 /**200 * Returns the HTTP headers that can be exposed as part of the response that have been defined.201 *202 * @returns {?string[]} An array of strings containing the headers or null if none has been defined.203 */204 getExposeHeaders(){205 return this._exposeHeaders;206 }207 /**208 * Sets how long CORS directives should be cached for on the client side, this method is chainable.209 *210 * @param {number} maxAge An integer number greater or equal than zero representing the how long cache should last in seconds, if zero no caching will be applied.211 *212 * @returns {CORSOptions}213 *214 * @throws {InvalidArgumentException} If an invalid max age value is given.215 */216 setMaxAge(maxAge){217 if ( maxAge === null || isNaN(maxAge) || maxAge < 0 ){218 throw new InvalidArgumentException('Invalid max age value.', 1);219 }220 this._maxAge = maxAge;221 return this;222 }223 /**224 * Returns how long CORS directives should be cached for on the client side.225 *226 * @returns {number} An integer number greater or equal than zero representing the how long cache should last in seconds or zero if no caching should be applied.227 */228 getMaxAge(){229 return this._maxAge;230 }231 /**232 * Sets if credentials (cookies, authorization headers or TLS client certificates) can be exposed to front-end, this method is chainable.233 *234 * @param {boolean} allowCredentials If set to "true" credentials will be allowed to be exposed to the front-end.235 *236 * @returns {CORSOptions}237 */238 setAllowCredentials(allowCredentials){239 this._allowCredentials = allowCredentials === true;240 return this;241 }242 /**243 * Returns if credentials (cookies, authorization headers or TLS client certificates) can be exposed to front-end.244 *245 * @returns {boolean} If credentials are allowed to be exposed to the front-end will be returned "true".246 */247 getAllowCredentials(){248 return this._allowCredentials === true;249 }250 /**251 * Sets the allowed HTTP methods, this method is chainable.252 *253 * @param {?string[]} allowMethods An array of strings containing the HTTP methods accepted for the incoming requests, if null any method will be accepted.254 *255 * @returns {CORSOptions}256 *257 * @throws {InvalidArgumentException} If an invalid method list is given.258 */259 setAllowMethods(allowMethods){260 if ( allowMethods !== null && !Array.isArray(allowMethods) ){261 throw new InvalidArgumentException('Invalid allowed HTTP methods list.', 1);262 }263 if ( allowMethods === null ){264 this._allowMethods = null;265 }else{266 // Normalize the given methods converting the into the upper case form.267 this._allowMethods = [];268 const length = allowMethods.length;269 for ( let i = 0 ; i < length ; i++ ){270 this._allowMethods.push(allowMethods[i].toUpperCase());271 }272 }273 return this;274 }275 /**276 * Returns the list of allowed HTTP methods.277 *278 * @returns {?string[]} An array of strings containing the HTTP methods defined or null if any method is accepted.279 */280 getAllowMethods(){281 return this._allowMethods;282 }283 /**284 * Sets the HTTP headers that can be included in client requests, this method is chainable.285 *286 * @param {?string[]} allowHeaders An array containing the list of HTTP headers, if null any header will be accepted.287 *288 * @returns {CORSOptions}289 *290 * @throws {InvalidArgumentException} If an invalid header list is given.291 */292 setAllowHeaders(allowHeaders){293 if ( allowHeaders !== null && !Array.isArray(allowHeaders) ){294 throw new InvalidArgumentException('Invalid allowed HTTP headers list.', 1);295 }296 if ( allowHeaders === null ){297 this._allowHeaders = null;298 }else{299 // Normalize the given headers converting the into the lower case form.300 this._allowHeaders = [];301 const length = allowHeaders.length;302 for ( let i = 0 ; i < length ; i++ ){303 this._allowHeaders.push(allowHeaders[i].toLowerCase());304 }305 }306 return this;307 }308 /**309 * Returns the list of HTTP headers that can be included in client requests.310 *311 * @returns {?string[]} An array containing the list of HTTP headers or null if any header is accepted.312 */313 getAllowHeaders(){314 return this._allowHeaders;315 }316 /**317 * Sets if an active check must be performed on incoming requests in order to reject the ones that doesn't meet the defined CORS settings, this method is chainable.318 *319 * @param {boolean} strict If set to "true" an active check will be performed on incoming requests.320 *321 * @returns {CORSOptions}322 */323 setStrict(strict){324 this._strict = strict === true;325 return this;326 }327 /**328 * Returns if an active check should be performed on incoming requests.329 *330 * @returns {boolean} If an active check is going to be performed will be returned "true".331 */332 getStrict(){333 return this._strict === true;334 }335 /**336 * Generates the HTTP headers to include in the client response.337 *338 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.339 * @param {module:http.ServerResponse} response An instance of the built-in class "ServerResponse" representing the response that will be sent back to the client.340 *341 * @returns {Object.<string, string>} An object containing the generated headers as key/value pairs.342 */343 buildHeaders(request, response){344 const headers = {};345 // Get or generate the allowed origin to declare.346 const origin = this._getComputedOrigin(request, response);347 if ( request.isPreflightRequest !== true || this._validateRequest(request, origin) ){348 // Current request is valid according to defined CORS options, declare the CORS headers.349 headers['Access-Control-Allow-Origin'] = origin === null ? '*' : origin;350 if ( this._allowCredentials === true ){351 headers['Access-Control-Allow-Credentials'] = 'true';352 }353 if ( this._exposeHeaders === null ){354 headers['Access-Control-Expose-Headers'] = '*';355 }else if ( Array.isArray(this._exposeHeaders) && this._exposeHeaders.length > 0 ){356 headers['Access-Control-Expose-Headers'] = this._exposeHeaders.join(', ');357 }358 if ( request.isPreflightRequest === true ){359 // Current request is a valid OPTIONS request, declare the remaining CORS options providing the full CORS policy to the client.360 if ( this._maxAge > 0 ){361 headers['Access-Control-Max-Age'] = this._maxAge;362 }363 if ( this._allowMethods === null ){364 headers['Access-Control-Allow-Methods'] = '*';365 }else if ( Array.isArray(this._allowMethods) && this._allowMethods.length > 0 ){366 headers['Access-Control-Allow-Methods'] = this._allowMethods.join(', ');367 }368 if ( this._allowHeaders === '*' ){369 headers['Access-Control-Allow-Headers'] = '*';370 }else if ( Array.isArray(this._allowHeaders) && this._allowHeaders.length > 0 ){371 headers['Access-Control-Allow-Headers'] = this._allowHeaders.join(', ');372 }373 }374 }375 return headers;376 }377 /**378 * Validates an incoming request according to defined CORS settings.379 *380 * @param {module:http.IncomingMessage} request An instance of the built-in class "IncomingMessage" containing all the connection properties.381 * @param {module:http.ServerResponse} response An instance of the built-in class "ServerResponse" representing the response that will be sent back to the client.382 *383 * @returns {boolean} If the given request meets the defined CORS settings will be returned "true".384 */385 validate(request, response){386 return this._strict !== true || this._validateRequest(request, this._getComputedOrigin(request, response));387 }388}...
implement-cors.js
Source:implement-cors.js
...11 if (originMatches(origin, corsOptions)) {12 taskContext.origin = origin;13 if (isSimpleRequest(taskContext)) {14 handleSimpleResponse(taskContext, corsOptions);15 } else if (isPreflightRequest(taskContext)) {16 /*17 * Stop the chain if we have created the response18 */19 if (handlePreflightResponse(taskContext, corsOptions)) return true;20 } else {21 handleSimpleResponse(taskContext, corsOptions);22 }23 } else {24 console.warn(`Cross-origin request to ${taskContext.urlInfo.apiURL} with origin ${origin} does not match allowed origins ${corsOptions.AccessControlAllowOrigin}`);25 }26 }27 }28 return taskContext;29};...
route-matching.js
Source:route-matching.js
...110 }111 return;112}113exports.getRouteForRequest = getRouteForRequest;114function isPreflightRequest(req) {115 return req.method === 'OPTIONS' && req.headers['access-control-request-method'];116}117/**118 * Is this a CORS preflight request that could be for an existing route?119 * If there is a matching route with method = 'OPTIONS', returns false.120 */121function matchesRoutePreflight(routes, req) {122 if (!isPreflightRequest(req)) {123 return false;124 }125 let hasCorsOverride = false;126 const matchingRoutes = lodash_1.default.filter(routes, ({ routeMatcher }) => {127 // omit headers from matching since preflight req will not send headers128 const preflightMatcher = lodash_1.default.omit(routeMatcher, 'method', 'headers', 'auth');129 if (!_doesRouteMatch(preflightMatcher, req)) {130 return false;131 }132 if (routeMatcher.method && /options/i.test(String(routeMatcher.method))) {133 hasCorsOverride = true;134 }135 return true;136 });...
cors-spec.js
Source:cors-spec.js
...8 req.headers = {};9 req.headers.origin = "abc.testy.com";10 req.headers['access-control-request-method'] = "PUT";11 req.method = "GET";12 assert.equal(cors.isPreflightRequest(req), false);13 });14 it('origin is not set', function () {15 var req = {};16 req.headers = {};17 req.headers['access-control-request-method'] = "PUT";18 req.method = "OPTIONS";19 assert.equal(cors.isPreflightRequest(req), false);20 });21 it('request method is not set', function () {22 var req = {};23 req.headers = {};24 req.headers.origin = "abc.testy.com";25 req.method = "OPTIONS";26 assert.equal(cors.isPreflightRequest(req), false);27 });28 it('origin is null string and referrer is trusted', function () {29 var req = {};30 req.headers = {};31 req.headers.origin = "null";32 req.method = "GET";33 req.headers.referer = "http://abc.testy.com/blah";34 assert.equal(cors.isPreflightRequest(req), false);35 });36 });37 describe('is in effect when', function(){38 it('cors preflight is detected', function () {39 var req = {};40 req.headers = {};41 req.headers.origin = "abc.testy.com";42 req.headers['access-control-request-method'] = "PUT";43 req.method = "OPTIONS";44 assert.equal(cors.isPreflightRequest(req), true);45 });46 it('origin is from an untrusted domain', function () {47 var req = {};48 req.headers = {};49 req.headers.origin = "abc.untrusted.com";50 req.method = "GET";51 assert.equal(cors.isOriginUntrusted(req), true);52 });53 it('origin is null string and referrer is untrusted', function () {54 var req = {};55 req.headers = {};56 req.headers.origin = 'null';57 req.method = "GET";58 req.headers.referer = "http://abc.untrusted.com/blah";...
Router.js
Source:Router.js
...23 const pageController = PageController(repository, user);24 return await pageController.handle(requestHelper);25 };26 const getResponse = async () => {27 if (requestHelper.isPreflightRequest()) {28 return {};29 }30 const path = requestHelper.getPath();31 const row = routes.find(([key, value]) => {32 return key === path;33 });34 if (row) {35 const [path, callback] = row;36 if (typeof callback === "function") {37 return await callback();38 }39 }40 return getErrorResponse();41 };...
index.js
Source:index.js
1require('dotenv').config();2const express = require('express');3const { getCategoriesRouter, getProductsRouter} = require('./productsOrCategoriesRoute.js');4const {handleLogInRoute, AUTH_TOKEN_HEADER_KEY} = require('./authentication.js');5const {sendErrorResponseToClient} = require('./helpers.js');6const {getEmailRouter} = require('./email.js');7const app = express();8app.use(express.json());9app.use(express.raw({type: "image/*", limit: "10mb"}));10function corsHandlerMiddleware(request, response, next){11 12 response.setHeader("Access-Control-Allow-Origin", "*");13 response.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");14 response.setHeader("Access-Control-Allow-Headers", `Content-Type, ${AUTH_TOKEN_HEADER_KEY}`);15 const isPreflightRequest = request.method === 'OPTIONS' && request.headers['origin'] && request.headers['access-control-request-method'];16 if (isPreflightRequest){17 response.end();18 return;19 }20 next();21}22app.use(corsHandlerMiddleware);23app.use('/login', handleLogInRoute);24app.use('/categories', getCategoriesRouter());25app.use('/products', getProductsRouter());26app.use('/email', getEmailRouter());27app.use((error, request, response, next) => {28 sendErrorResponseToClient(response, error);29});30const port = process.env.PORT || 5000;...
RequestHelper.js
Source:RequestHelper.js
1const RequestHelper = req => {2 const getQueryData = () => {3 return req.query;4 };5 const isPostRequest = () => {6 return req.method === 'POST';7 };8 const isPreflightRequest = () => {9 return req.method === 'OPTIONS';10 };11 const getBodyData = async () => {12 if (isPostRequest() === false) {13 return null;14 }15 let chunks = [];16 await req.on('data', chunk => {17 chunks.push(chunk);18 });19 return Buffer.concat(chunks).toString();20 };21 const getJsonData = async () => {22 const body = await getBodyData();23 if (body) {24 return JSON.parse(body);25 }26 return null;27 };28 const getHeaders = () => {29 return req.headers;30 };31 const getHeader = key => {32 return req.headers[key] || null;33 };34 const getPath = () => {35 return req.path;36 };37 return {38 getQueryData,39 isPostRequest,40 isPreflightRequest,41 getBodyData,42 getJsonData,43 getHeaders,44 getHeader,45 getPath,46 }47};...
Using AI Code Generation
1describe('Cypress.isPreflightRequest', () => {2 it('is a preflight request', () => {3 onBeforeLoad(win) {4 cy.stub(win, 'fetch').as('windowFetch')5 },6 })7 cy.get('#login').click()8 cy.get('@windowFetch').then((fetch) => {9 expect(Cypress.isPreflightRequest(fetch.getCall(0).args[0])).to.be.true10 })11 })12})13describe('Cypress.isPreflightRequest', () => {14 it('is a preflight request', () => {15 onBeforeLoad(win) {16 cy.stub(win, 'fetch').as('windowFetch')17 },18 })19 cy.get('#login').click()20 cy.get('@windowFetch').then((fetch) => {21 expect(Cypress.isPreflightRequest(fetch.getCall(0).args[0])).to.be.true22 })23 })24})25describe('Cypress.isPreflightRequest', () => {26 it('is a preflight request', () => {27 onBeforeLoad(win) {28 cy.stub(win, 'fetch').as('windowFetch')29 },30 })31 cy.get('#login').click()32 cy.get('@windowFetch').then((fetch) => {33 expect(Cypress.isPreflightRequest(fetch.getCall(0).args[0])).to.be.true34 })35 })36})37describe('Cypress.isPreflightRequest', () => {38 it('is a preflight request', () => {39 onBeforeLoad(win) {40 cy.stub(win, 'fetch').as('windowFetch')41 },42 })43 cy.get('#login').click()44 cy.get('@windowFetch').then((fetch) => {45 expect(Cypress.isPreflightRequest(fetch.getCall(0).args[0
Using AI Code Generation
1Cypress.Commands.overwrite('request', (originalFn, ...options) => {2 if (isPreflightRequest(options)) {3 options = setPreflightHeaders(options);4 }5 return originalFn(...options);6});7function isPreflightRequest(options) {8 return options.method === 'POST' || options.method === 'PUT';9}10function setPreflightHeaders(options) {11 options.headers = {12 };13 options.method = 'OPTIONS';14 return options;15}
Using AI Code Generation
1const isPreflightRequest = (request) => {2};3const isPreflightRequest = (request) => {4};5const isPreflightRequest = (request) => {6};7const isPreflightRequest = (request) => {8};9const isPreflightRequest = (request) => {10};11const isPreflightRequest = (request) => {12};13const isPreflightRequest = (request) => {14};15const isPreflightRequest = (request) => {16};17const isPreflightRequest = (request) => {18};19const isPreflightRequest = (request) => {20};21const isPreflightRequest = (request) => {22};23const isPreflightRequest = (request) => {24};25const isPreflightRequest = (
Using AI Code Generation
1describe('Cypress.isPreflightRequest', () => {2 it('should return false for non-preflight requests', () => {3 cy.server()4 cy.route('POST', '**/comments').as('postComment')5 cy.get('.network-post').click()6 cy.wait('@postComment').then((xhr) => {7 expect(xhr.response.body).to.have.property('name', 'Using POST in cy.route()')8 expect(Cypress.isPreflightRequest(xhr.request)).to.be.false9 })10 })11})12const getComments = () => {13 name: 'Using POST in cy.route()',14 })15}16const attachCommentsToDOM = (comments) => {17 return cy.get('.network-post-comment').append(comments)18}19const isPreflightRequest = (xhr) => {20}21$('.network-post').click(() => {22 getComments()23 .then((xhr) => {24 if (isPreflightRequest(xhr)) {25 }26 attachCommentsToDOM(xhr.response.body)27 })28})29const getComments = () => {30 name: 'Using POST in cy.route()',31 })32}33const attachCommentsToDOM = (comments) => {34 return cy.get('.network-post-comment').append(comments)35}36$('.network-post').click(() => {37 getComments()38 .then((xhr) => {39 if (Cypress.isPreflightRequest(xhr)) {40 }41 attachCommentsToDOM(xhr.response.body)42 })43})
Using AI Code Generation
1describe('Test', () => {2 it('Test', () => {3 cy.server()4 cy.route('POST', '/api/login').as('login')5 cy.get('[data-cy=username]').type('test')6 cy.get('[data-cy=password]').type('test')7 cy.get('[data-cy=login]').click()8 cy.wait('@login').then((xhr) => {9 expect(xhr.isPreflightRequest).to.equal(false)10 })11 })12})13{14 "reporterOptions": {},15}16module.exports = (on, config) => {17}18import './commands'19Cypress.Commands.add('login', (username, password) => {20 cy.visit('/login')21 cy.get('[data-cy=username]').type(username)22 cy.get('[data-cy=password]').type(password)23 cy.get('[data-cy=login]').click()24})25Cypress.Commands.add('drag', { prevSubject: 'element' }, (subject, options) => {26 cy.wrap(subject
Using AI Code Generation
1describe('Preflight request', () => {2 it('should check preflight request', () => {3 let isPreflightRequest = Cypress.isPreflightRequest;4 onBeforeLoad: (win) => {5 cy.stub(win, 'fetch').callsFake((...args) => {6 const [url, options] = args;7 if (isPreflightRequest(url, options)) {8 return Promise.resolve(new Response(null, { status: 204 }));9 }10 return window.fetch(...args);11 });12 }13 });14 });15});16describe('Preflight request', () => {17 it('should check preflight request', () => {18 cy.intercept('OPTIONS', '**', (req) => {19 req.reply();20 });21 });22});
Using AI Code Generation
1it('test', () => {2 cy.server();3 cy.route('POST', '/users', 'fixture:users.json').as('createUser');4 cy.get('#form-first-name').type('Jane');5 cy.get('#form-last-name').type('Doe');6 cy.get('#form-submit').click();7 cy.wait('@createUser').its('request').should('be.preflightRequest');8});9.isPreflightRequest()10cy.route('POST', '/users', 'fixture:users.json').as('createUser');11cy.wait('@createUser').its('request').should('be.preflightRequest');
Cypress is a renowned Javascript-based open-source, easy-to-use end-to-end testing framework primarily used for testing web applications. Cypress is a relatively new player in the automation testing space and has been gaining much traction lately, as evidenced by the number of Forks (2.7K) and Stars (42.1K) for the project. LambdaTest’s Cypress Tutorial covers step-by-step guides that will help you learn from the basics till you run automation tests on LambdaTest.
You can elevate your expertise with end-to-end testing using the Cypress automation framework and stay one step ahead in your career by earning a Cypress certification. Check out our Cypress 101 Certification.
Watch this 3 hours of complete tutorial to learn the basics of Cypress and various Cypress commands with the Cypress testing at LambdaTest.
Get 100 minutes of automation test minutes FREE!!