CookieParser.js 4.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. export default class CookieParser{constructor(){}
  2. static parseCookie(header){return(new CookieParser()).parseCookie(header);}
  3. static parseSetCookie(header){return(new CookieParser()).parseSetCookie(header);}
  4. cookies(){return this._cookies;}
  5. parseCookie(cookieHeader){if(!this._initialize(cookieHeader)){return null;}
  6. for(let kv=this._extractKeyValue();kv;kv=this._extractKeyValue()){if(kv.key.charAt(0)==='$'&&this._lastCookie){this._lastCookie.addAttribute(kv.key.slice(1),kv.value);}else if(kv.key.toLowerCase()!=='$version'&&typeof kv.value==='string'){this._addCookie(kv,Type.Request);}
  7. this._advanceAndCheckCookieDelimiter();}
  8. this._flushCookie();return this._cookies;}
  9. parseSetCookie(setCookieHeader){if(!this._initialize(setCookieHeader)){return null;}
  10. for(let kv=this._extractKeyValue();kv;kv=this._extractKeyValue()){if(this._lastCookie){this._lastCookie.addAttribute(kv.key,kv.value);}else{this._addCookie(kv,Type.Response);}
  11. if(this._advanceAndCheckCookieDelimiter()){this._flushCookie();}}
  12. this._flushCookie();return this._cookies;}
  13. _initialize(headerValue){this._input=headerValue;if(typeof headerValue!=='string'){return false;}
  14. this._cookies=[];this._lastCookie=null;this._lastCookieLine='';this._originalInputLength=this._input.length;return true;}
  15. _flushCookie(){if(this._lastCookie){this._lastCookie.setSize(this._originalInputLength-this._input.length-this._lastCookiePosition);this._lastCookie._setCookieLine(this._lastCookieLine.replace('\n',''));}
  16. this._lastCookie=null;this._lastCookieLine='';}
  17. _extractKeyValue(){if(!this._input||!this._input.length){return null;}
  18. const keyValueMatch=/^[ \t]*([^\s=;]+)[ \t]*(?:=[ \t]*([^;\n]*))?/.exec(this._input);if(!keyValueMatch){console.error('Failed parsing cookie header before: '+this._input);return null;}
  19. const result=new KeyValue(keyValueMatch[1],keyValueMatch[2]&&keyValueMatch[2].trim(),this._originalInputLength-this._input.length);this._lastCookieLine+=keyValueMatch[0];this._input=this._input.slice(keyValueMatch[0].length);return result;}
  20. _advanceAndCheckCookieDelimiter(){const match=/^\s*[\n;]\s*/.exec(this._input);if(!match){return false;}
  21. this._lastCookieLine+=match[0];this._input=this._input.slice(match[0].length);return match[0].match('\n')!==null;}
  22. _addCookie(keyValue,type){if(this._lastCookie){this._lastCookie.setSize(keyValue.position-this._lastCookiePosition);}
  23. this._lastCookie=typeof keyValue.value==='string'?new SDK.Cookie(keyValue.key,keyValue.value,type):new SDK.Cookie('',keyValue.key,type);this._lastCookiePosition=keyValue.position;this._cookies.push(this._lastCookie);}}
  24. class KeyValue{constructor(key,value,position){this.key=key;this.value=value;this.position=position;}}
  25. export class Cookie{constructor(name,value,type){this._name=name;this._value=value;this._type=type;this._attributes={};this._size=0;this._cookieLine=null;}
  26. static fromProtocolCookie(protocolCookie){const cookie=new SDK.Cookie(protocolCookie.name,protocolCookie.value,null);cookie.addAttribute('domain',protocolCookie['domain']);cookie.addAttribute('path',protocolCookie['path']);cookie.addAttribute('port',protocolCookie['port']);if(protocolCookie['expires']){cookie.addAttribute('expires',protocolCookie['expires']*1000);}
  27. if(protocolCookie['httpOnly']){cookie.addAttribute('httpOnly');}
  28. if(protocolCookie['secure']){cookie.addAttribute('secure');}
  29. if(protocolCookie['sameSite']){cookie.addAttribute('sameSite',protocolCookie['sameSite']);}
  30. cookie.setSize(protocolCookie['size']);return cookie;}
  31. name(){return this._name;}
  32. value(){return this._value;}
  33. type(){return this._type;}
  34. httpOnly(){return'httponly'in this._attributes;}
  35. secure(){return'secure'in this._attributes;}
  36. sameSite(){return(this._attributes['samesite']);}
  37. session(){return!('expires'in this._attributes||'max-age'in this._attributes);}
  38. path(){return this._attributes['path'];}
  39. port(){return this._attributes['port'];}
  40. domain(){return this._attributes['domain'];}
  41. expires(){return this._attributes['expires'];}
  42. maxAge(){return this._attributes['max-age'];}
  43. size(){return this._size;}
  44. url(){return(this.secure()?'https://':'http://')+this.domain()+this.path();}
  45. setSize(size){this._size=size;}
  46. expiresDate(requestDate){if(this.maxAge()){const targetDate=requestDate===null?new Date():requestDate;return new Date(targetDate.getTime()+1000*this.maxAge());}
  47. if(this.expires()){return new Date(this.expires());}
  48. return null;}
  49. attributes(){return this._attributes;}
  50. addAttribute(key,value){this._attributes[key.toLowerCase()]=value;}
  51. _setCookieLine(cookieLine){this._cookieLine=cookieLine;}
  52. getCookieLine(){return this._cookieLine;}}
  53. export const Type={Request:0,Response:1};export const Attributes={Name:'name',Value:'value',Size:'size',Domain:'domain',Path:'path',Expires:'expires',HttpOnly:'httpOnly',Secure:'secure',SameSite:'sameSite',};self.SDK=self.SDK||{};SDK=SDK||{};SDK.CookieParser=CookieParser;SDK.Cookie=Cookie;SDK.Cookie.Type=Type;SDK.Cookie.Attributes=Attributes;