head_cookies.js (46466B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ 3 */ 4 5 /* import-globals-from head_cache.js */ 6 7 "use strict"; 8 9 const { NetUtil } = ChromeUtils.importESModule( 10 "resource://gre/modules/NetUtil.sys.mjs" 11 ); 12 const { CookieXPCShellUtils } = ChromeUtils.importESModule( 13 "resource://testing-common/CookieXPCShellUtils.sys.mjs" 14 ); 15 16 // Don't pick up default permissions from profile. 17 Services.prefs.setCharPref("permissions.manager.defaultsUrl", ""); 18 19 CookieXPCShellUtils.init(this); 20 21 function do_check_throws(f, result, stack) { 22 if (!stack) { 23 stack = Components.stack.caller; 24 } 25 26 try { 27 f(); 28 } catch (exc) { 29 if (exc.result == result) { 30 return; 31 } 32 do_throw("expected result " + result + ", caught " + exc, stack); 33 } 34 do_throw("expected result " + result + ", none thrown", stack); 35 } 36 37 // Helper to step a generator function and catch a StopIteration exception. 38 function do_run_generator(generator) { 39 try { 40 generator.next(); 41 } catch (e) { 42 do_throw("caught exception " + e, Components.stack.caller); 43 } 44 } 45 46 // Helper to finish a generator function test. 47 function do_finish_generator_test(generator) { 48 executeSoon(function () { 49 generator.return(); 50 do_test_finished(); 51 }); 52 } 53 54 function _observer(generator, topic) { 55 Services.obs.addObserver(this, topic); 56 57 this.generator = generator; 58 this.topic = topic; 59 } 60 61 _observer.prototype = { 62 observe(subject, topic) { 63 Assert.equal(this.topic, topic); 64 65 Services.obs.removeObserver(this, this.topic); 66 67 // Continue executing the generator function. 68 if (this.generator) { 69 do_run_generator(this.generator); 70 } 71 72 this.generator = null; 73 this.topic = null; 74 }, 75 }; 76 77 // Close the cookie database. If a generator is supplied, it will be invoked 78 // once the close is complete. 79 function do_close_profile(generator) { 80 // Register an observer for db close. 81 new _observer(generator, "cookie-db-closed"); 82 83 // Close the db. 84 let service = Services.cookies.QueryInterface(Ci.nsIObserver); 85 service.observe(null, "profile-before-change", null); 86 } 87 88 function _promise_observer(topic) { 89 Services.obs.addObserver(this, topic); 90 91 this.topic = topic; 92 return new Promise(resolve => (this.resolve = resolve)); 93 } 94 95 _promise_observer.prototype = { 96 observe(subject, topic) { 97 Assert.equal(this.topic, topic); 98 99 Services.obs.removeObserver(this, this.topic); 100 if (this.resolve) { 101 this.resolve(); 102 } 103 104 this.resolve = null; 105 this.topic = null; 106 }, 107 }; 108 109 // Close the cookie database. And resolve a promise. 110 function promise_close_profile() { 111 // Register an observer for db close. 112 let promise = new _promise_observer("cookie-db-closed"); 113 114 // Close the db. 115 let service = Services.cookies.QueryInterface(Ci.nsIObserver); 116 service.observe(null, "profile-before-change", null); 117 118 return promise; 119 } 120 121 // Load the cookie database. 122 function promise_load_profile() { 123 // Register an observer for read completion. 124 let promise = new _promise_observer("cookie-db-read"); 125 126 // Load the profile. 127 let service = Services.cookies.QueryInterface(Ci.nsIObserver); 128 service.observe(null, "profile-do-change", ""); 129 130 return promise; 131 } 132 133 // Load the cookie database. If a generator is supplied, it will be invoked 134 // once the load is complete. 135 function do_load_profile(generator) { 136 // Register an observer for read completion. 137 new _observer(generator, "cookie-db-read"); 138 139 // Load the profile. 140 let service = Services.cookies.QueryInterface(Ci.nsIObserver); 141 service.observe(null, "profile-do-change", ""); 142 } 143 144 // Set a single session cookie using http and test the cookie count 145 // against 'expected' 146 function do_set_single_http_cookie(uri, channel, expected) { 147 Services.cookies.setCookieStringFromHttp(uri, "foo=bar", channel); 148 Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected); 149 } 150 151 // Set two cookies; via document.channel and via http request. 152 async function do_set_cookies(uri, channel, session, expected) { 153 let suffix = session ? "" : "; max-age=1000"; 154 155 // via document.cookie 156 const thirdPartyUrl = "http://third.com/"; 157 const contentPage = await CookieXPCShellUtils.loadContentPage(thirdPartyUrl); 158 await contentPage.spawn( 159 [ 160 { 161 cookie: "can=has" + suffix, 162 url: uri.spec, 163 }, 164 ], 165 async function (obj) { 166 await new this.content.Promise(resolve => { 167 let doc = this.content.document; 168 let ifr = doc.createElement("iframe"); 169 ifr.src = obj.url; 170 doc.body.appendChild(ifr); 171 ifr.addEventListener("load", async () => { 172 await this.SpecialPowers.spawn(ifr, [obj.cookie], cookie => { 173 this.content.document.cookie = cookie; 174 }); 175 resolve(); 176 }); 177 }); 178 } 179 ); 180 await contentPage.close(); 181 182 Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected[0]); 183 184 // via http request 185 Services.cookies.setCookieStringFromHttp(uri, "hot=dog" + suffix, channel); 186 Assert.equal(Services.cookies.countCookiesFromHost(uri.host), expected[1]); 187 } 188 189 function do_count_cookies() { 190 return Services.cookies.cookies.length; 191 } 192 193 // Helper object to store cookie data. 194 function Cookie( 195 name, 196 value, 197 host, 198 path, 199 expiry, 200 lastAccessed, 201 creationTime, 202 isSession, 203 isSecure, 204 isHttpOnly, 205 inBrowserElement = false, 206 originAttributes = {}, 207 sameSite = Ci.nsICookie.SAMESITE_UNSET, 208 schemeMap = Ci.nsICookie.SCHEME_UNSET, 209 isPartitioned = false, 210 updateTime = null 211 ) { 212 this.name = name; 213 this.value = value; 214 this.host = host; 215 this.path = path; 216 this.expiry = expiry; 217 this.lastAccessed = lastAccessed; 218 this.creationTime = creationTime; 219 this.isSession = isSession; 220 this.isSecure = isSecure; 221 this.isHttpOnly = isHttpOnly; 222 this.inBrowserElement = inBrowserElement; 223 this.originAttributes = originAttributes; 224 this.sameSite = sameSite; 225 this.schemeMap = schemeMap; 226 this.isPartitioned = isPartitioned; 227 this.updateTime = updateTime || creationTime; 228 229 // For pre version 15 compatibility: 230 this.rawSameSite = sameSite; 231 232 let strippedHost = host.charAt(0) == "." ? host.slice(1) : host; 233 234 try { 235 this.baseDomain = Services.eTLD.getBaseDomainFromHost(strippedHost); 236 } catch (e) { 237 if ( 238 e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS || 239 e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS 240 ) { 241 this.baseDomain = strippedHost; 242 } 243 } 244 } 245 246 // Object representing a database connection and associated statements. The 247 // implementation varies depending on schema version. 248 function CookieDatabaseConnection(file, schema) { 249 // Manually generate a cookies.sqlite file with appropriate rows, columns, 250 // and schema version. If it already exists, just set up our statements. 251 let exists = file.exists(); 252 253 this.db = Services.storage.openDatabase(file); 254 this.schema = schema; 255 if (!exists) { 256 this.db.schemaVersion = schema; 257 } 258 259 switch (schema) { 260 case 1: { 261 if (!exists) { 262 this.db.executeSimpleSQL( 263 "CREATE TABLE moz_cookies ( \ 264 id INTEGER PRIMARY KEY, \ 265 name TEXT, \ 266 value TEXT, \ 267 host TEXT, \ 268 path TEXT, \ 269 expiry INTEGER, \ 270 isSecure INTEGER, \ 271 isHttpOnly INTEGER)" 272 ); 273 } 274 275 this.stmtInsert = this.db.createStatement( 276 "INSERT INTO moz_cookies ( \ 277 id, \ 278 name, \ 279 value, \ 280 host, \ 281 path, \ 282 expiry, \ 283 isSecure, \ 284 isHttpOnly) \ 285 VALUES ( \ 286 :id, \ 287 :name, \ 288 :value, \ 289 :host, \ 290 :path, \ 291 :expiry, \ 292 :isSecure, \ 293 :isHttpOnly)" 294 ); 295 296 this.stmtDelete = this.db.createStatement( 297 "DELETE FROM moz_cookies WHERE id = :id" 298 ); 299 300 break; 301 } 302 303 case 2: { 304 if (!exists) { 305 this.db.executeSimpleSQL( 306 "CREATE TABLE moz_cookies ( \ 307 id INTEGER PRIMARY KEY, \ 308 name TEXT, \ 309 value TEXT, \ 310 host TEXT, \ 311 path TEXT, \ 312 expiry INTEGER, \ 313 lastAccessed INTEGER, \ 314 isSecure INTEGER, \ 315 isHttpOnly INTEGER)" 316 ); 317 } 318 319 this.stmtInsert = this.db.createStatement( 320 "INSERT OR REPLACE INTO moz_cookies ( \ 321 id, \ 322 name, \ 323 value, \ 324 host, \ 325 path, \ 326 expiry, \ 327 lastAccessed, \ 328 isSecure, \ 329 isHttpOnly) \ 330 VALUES ( \ 331 :id, \ 332 :name, \ 333 :value, \ 334 :host, \ 335 :path, \ 336 :expiry, \ 337 :lastAccessed, \ 338 :isSecure, \ 339 :isHttpOnly)" 340 ); 341 342 this.stmtDelete = this.db.createStatement( 343 "DELETE FROM moz_cookies WHERE id = :id" 344 ); 345 346 this.stmtUpdate = this.db.createStatement( 347 "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id" 348 ); 349 350 break; 351 } 352 353 case 3: { 354 if (!exists) { 355 this.db.executeSimpleSQL( 356 "CREATE TABLE moz_cookies ( \ 357 id INTEGER PRIMARY KEY, \ 358 baseDomain TEXT, \ 359 name TEXT, \ 360 value TEXT, \ 361 host TEXT, \ 362 path TEXT, \ 363 expiry INTEGER, \ 364 lastAccessed INTEGER, \ 365 isSecure INTEGER, \ 366 isHttpOnly INTEGER)" 367 ); 368 369 this.db.executeSimpleSQL( 370 "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)" 371 ); 372 } 373 374 this.stmtInsert = this.db.createStatement( 375 "INSERT INTO moz_cookies ( \ 376 id, \ 377 baseDomain, \ 378 name, \ 379 value, \ 380 host, \ 381 path, \ 382 expiry, \ 383 lastAccessed, \ 384 isSecure, \ 385 isHttpOnly) \ 386 VALUES ( \ 387 :id, \ 388 :baseDomain, \ 389 :name, \ 390 :value, \ 391 :host, \ 392 :path, \ 393 :expiry, \ 394 :lastAccessed, \ 395 :isSecure, \ 396 :isHttpOnly)" 397 ); 398 399 this.stmtDelete = this.db.createStatement( 400 "DELETE FROM moz_cookies WHERE id = :id" 401 ); 402 403 this.stmtUpdate = this.db.createStatement( 404 "UPDATE moz_cookies SET lastAccessed = :lastAccessed WHERE id = :id" 405 ); 406 407 break; 408 } 409 410 case 4: { 411 if (!exists) { 412 this.db.executeSimpleSQL( 413 "CREATE TABLE moz_cookies ( \ 414 id INTEGER PRIMARY KEY, \ 415 baseDomain TEXT, \ 416 name TEXT, \ 417 value TEXT, \ 418 host TEXT, \ 419 path TEXT, \ 420 expiry INTEGER, \ 421 lastAccessed INTEGER, \ 422 creationTime INTEGER, \ 423 isSecure INTEGER, \ 424 isHttpOnly INTEGER \ 425 CONSTRAINT moz_uniqueid UNIQUE (name, host, path))" 426 ); 427 428 this.db.executeSimpleSQL( 429 "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)" 430 ); 431 432 this.db.executeSimpleSQL("PRAGMA journal_mode = WAL"); 433 } 434 435 this.stmtInsert = this.db.createStatement( 436 "INSERT INTO moz_cookies ( \ 437 baseDomain, \ 438 name, \ 439 value, \ 440 host, \ 441 path, \ 442 expiry, \ 443 lastAccessed, \ 444 creationTime, \ 445 isSecure, \ 446 isHttpOnly) \ 447 VALUES ( \ 448 :baseDomain, \ 449 :name, \ 450 :value, \ 451 :host, \ 452 :path, \ 453 :expiry, \ 454 :lastAccessed, \ 455 :creationTime, \ 456 :isSecure, \ 457 :isHttpOnly)" 458 ); 459 460 this.stmtDelete = this.db.createStatement( 461 "DELETE FROM moz_cookies \ 462 WHERE name = :name AND host = :host AND path = :path" 463 ); 464 465 this.stmtUpdate = this.db.createStatement( 466 "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ 467 WHERE name = :name AND host = :host AND path = :path" 468 ); 469 470 break; 471 } 472 473 case 10: { 474 if (!exists) { 475 this.db.executeSimpleSQL( 476 "CREATE TABLE moz_cookies ( \ 477 id INTEGER PRIMARY KEY, \ 478 baseDomain TEXT, \ 479 originAttributes TEXT NOT NULL DEFAULT '', \ 480 name TEXT, \ 481 value TEXT, \ 482 host TEXT, \ 483 path TEXT, \ 484 expiry INTEGER, \ 485 lastAccessed INTEGER, \ 486 creationTime INTEGER, \ 487 isSecure INTEGER, \ 488 isHttpOnly INTEGER, \ 489 inBrowserElement INTEGER DEFAULT 0, \ 490 sameSite INTEGER DEFAULT 0, \ 491 rawSameSite INTEGER DEFAULT 0, \ 492 CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))" 493 ); 494 495 this.db.executeSimpleSQL( 496 "CREATE INDEX moz_basedomain ON moz_cookies (baseDomain)" 497 ); 498 499 this.db.executeSimpleSQL("PRAGMA journal_mode = WAL"); 500 this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); 501 } 502 503 this.stmtInsert = this.db.createStatement( 504 "INSERT INTO moz_cookies ( \ 505 name, \ 506 value, \ 507 host, \ 508 baseDomain, \ 509 path, \ 510 expiry, \ 511 lastAccessed, \ 512 creationTime, \ 513 isSecure, \ 514 isHttpOnly, \ 515 inBrowserElement, \ 516 originAttributes, \ 517 sameSite, \ 518 rawSameSite \ 519 ) VALUES ( \ 520 :name, \ 521 :value, \ 522 :host, \ 523 :baseDomain, \ 524 :path, \ 525 :expiry, \ 526 :lastAccessed, \ 527 :creationTime, \ 528 :isSecure, \ 529 :isHttpOnly, \ 530 :inBrowserElement, \ 531 :originAttributes, \ 532 :sameSite, \ 533 :rawSameSite)" 534 ); 535 536 this.stmtDelete = this.db.createStatement( 537 "DELETE FROM moz_cookies \ 538 WHERE name = :name AND host = :host AND path = :path AND \ 539 originAttributes = :originAttributes" 540 ); 541 542 this.stmtUpdate = this.db.createStatement( 543 "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ 544 WHERE name = :name AND host = :host AND path = :path AND \ 545 originAttributes = :originAttributes" 546 ); 547 548 break; 549 } 550 551 case 11: { 552 if (!exists) { 553 this.db.executeSimpleSQL( 554 "CREATE TABLE moz_cookies ( \ 555 id INTEGER PRIMARY KEY, \ 556 originAttributes TEXT NOT NULL DEFAULT '', \ 557 name TEXT, \ 558 value TEXT, \ 559 host TEXT, \ 560 path TEXT, \ 561 expiry INTEGER, \ 562 lastAccessed INTEGER, \ 563 creationTime INTEGER, \ 564 isSecure INTEGER, \ 565 isHttpOnly INTEGER, \ 566 inBrowserElement INTEGER DEFAULT 0, \ 567 sameSite INTEGER DEFAULT 0, \ 568 rawSameSite INTEGER DEFAULT 0, \ 569 CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))" 570 ); 571 572 this.db.executeSimpleSQL("PRAGMA journal_mode = WAL"); 573 this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); 574 } 575 576 this.stmtInsert = this.db.createStatement( 577 "INSERT INTO moz_cookies ( \ 578 name, \ 579 value, \ 580 host, \ 581 path, \ 582 expiry, \ 583 lastAccessed, \ 584 creationTime, \ 585 isSecure, \ 586 isHttpOnly, \ 587 inBrowserElement, \ 588 originAttributes, \ 589 sameSite, \ 590 rawSameSite \ 591 ) VALUES ( \ 592 :name, \ 593 :value, \ 594 :host, \ 595 :path, \ 596 :expiry, \ 597 :lastAccessed, \ 598 :creationTime, \ 599 :isSecure, \ 600 :isHttpOnly, \ 601 :inBrowserElement, \ 602 :originAttributes, \ 603 :sameSite, \ 604 :rawSameSite)" 605 ); 606 607 this.stmtDelete = this.db.createStatement( 608 "DELETE FROM moz_cookies \ 609 WHERE name = :name AND host = :host AND path = :path AND \ 610 originAttributes = :originAttributes" 611 ); 612 613 this.stmtUpdate = this.db.createStatement( 614 "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ 615 WHERE name = :name AND host = :host AND path = :path AND \ 616 originAttributes = :originAttributes" 617 ); 618 619 break; 620 } 621 622 case 12: { 623 if (!exists) { 624 this.db.executeSimpleSQL( 625 "CREATE TABLE moz_cookies ( \ 626 id INTEGER PRIMARY KEY, \ 627 originAttributes TEXT NOT NULL DEFAULT '', \ 628 name TEXT, \ 629 value TEXT, \ 630 host TEXT, \ 631 path TEXT, \ 632 expiry INTEGER, \ 633 lastAccessed INTEGER, \ 634 creationTime INTEGER, \ 635 isSecure INTEGER, \ 636 isHttpOnly INTEGER, \ 637 inBrowserElement INTEGER DEFAULT 0, \ 638 sameSite INTEGER DEFAULT 0, \ 639 rawSameSite INTEGER DEFAULT 0, \ 640 schemeMap INTEGER DEFAULT 0, \ 641 CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))" 642 ); 643 644 this.db.executeSimpleSQL("PRAGMA journal_mode = WAL"); 645 this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); 646 } 647 648 this.stmtInsert = this.db.createStatement( 649 "INSERT INTO moz_cookies ( \ 650 name, \ 651 value, \ 652 host, \ 653 path, \ 654 expiry, \ 655 lastAccessed, \ 656 creationTime, \ 657 isSecure, \ 658 isHttpOnly, \ 659 inBrowserElement, \ 660 originAttributes, \ 661 sameSite, \ 662 rawSameSite, \ 663 schemeMap \ 664 ) VALUES ( \ 665 :name, \ 666 :value, \ 667 :host, \ 668 :path, \ 669 :expiry, \ 670 :lastAccessed, \ 671 :creationTime, \ 672 :isSecure, \ 673 :isHttpOnly, \ 674 :inBrowserElement, \ 675 :originAttributes, \ 676 :sameSite, \ 677 :rawSameSite, \ 678 :schemeMap)" 679 ); 680 681 this.stmtDelete = this.db.createStatement( 682 "DELETE FROM moz_cookies \ 683 WHERE name = :name AND host = :host AND path = :path AND \ 684 originAttributes = :originAttributes" 685 ); 686 687 this.stmtUpdate = this.db.createStatement( 688 "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ 689 WHERE name = :name AND host = :host AND path = :path AND \ 690 originAttributes = :originAttributes" 691 ); 692 693 break; 694 } 695 696 case 13: 697 case 14: { 698 if (!exists) { 699 this.db.executeSimpleSQL( 700 "CREATE TABLE moz_cookies ( \ 701 id INTEGER PRIMARY KEY, \ 702 originAttributes TEXT NOT NULL DEFAULT '', \ 703 name TEXT, \ 704 value TEXT, \ 705 host TEXT, \ 706 path TEXT, \ 707 expiry INTEGER, \ 708 lastAccessed INTEGER, \ 709 creationTime INTEGER, \ 710 isSecure INTEGER, \ 711 isHttpOnly INTEGER, \ 712 inBrowserElement INTEGER DEFAULT 0, \ 713 sameSite INTEGER DEFAULT 0, \ 714 rawSameSite INTEGER DEFAULT 0, \ 715 schemeMap INTEGER DEFAULT 0, \ 716 isPartitionedAttributeSet INTEGER DEFAULT 0, \ 717 CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))" 718 ); 719 720 this.db.executeSimpleSQL("PRAGMA journal_mode = WAL"); 721 this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); 722 } 723 724 this.stmtInsert = this.db.createStatement( 725 "INSERT INTO moz_cookies ( \ 726 name, \ 727 value, \ 728 host, \ 729 path, \ 730 expiry, \ 731 lastAccessed, \ 732 creationTime, \ 733 isSecure, \ 734 isHttpOnly, \ 735 inBrowserElement, \ 736 originAttributes, \ 737 sameSite, \ 738 rawSameSite, \ 739 schemeMap, \ 740 isPartitionedAttributeSet \ 741 ) VALUES ( \ 742 :name, \ 743 :value, \ 744 :host, \ 745 :path, \ 746 :expiry, \ 747 :lastAccessed, \ 748 :creationTime, \ 749 :isSecure, \ 750 :isHttpOnly, \ 751 :inBrowserElement, \ 752 :originAttributes, \ 753 :sameSite, \ 754 :rawSameSite, \ 755 :schemeMap, \ 756 :isPartitionedAttributeSet)" 757 ); 758 759 this.stmtDelete = this.db.createStatement( 760 "DELETE FROM moz_cookies \ 761 WHERE name = :name AND host = :host AND path = :path AND \ 762 originAttributes = :originAttributes" 763 ); 764 765 this.stmtUpdate = this.db.createStatement( 766 "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ 767 WHERE name = :name AND host = :host AND path = :path AND \ 768 originAttributes = :originAttributes" 769 ); 770 771 break; 772 } 773 case 15: 774 case 16: { 775 if (!exists) { 776 this.db.executeSimpleSQL( 777 "CREATE TABLE moz_cookies ( \ 778 id INTEGER PRIMARY KEY, \ 779 originAttributes TEXT NOT NULL DEFAULT '', \ 780 name TEXT, \ 781 value TEXT, \ 782 host TEXT, \ 783 path TEXT, \ 784 expiry INTEGER, \ 785 lastAccessed INTEGER, \ 786 creationTime INTEGER, \ 787 isSecure INTEGER, \ 788 isHttpOnly INTEGER, \ 789 inBrowserElement INTEGER DEFAULT 0, \ 790 sameSite INTEGER DEFAULT 0, \ 791 schemeMap INTEGER DEFAULT 0, \ 792 isPartitionedAttributeSet INTEGER DEFAULT 0, \ 793 CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))" 794 ); 795 796 this.db.executeSimpleSQL("PRAGMA journal_mode = WAL"); 797 this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); 798 } 799 800 this.stmtInsert = this.db.createStatement( 801 "INSERT INTO moz_cookies ( \ 802 name, \ 803 value, \ 804 host, \ 805 path, \ 806 expiry, \ 807 lastAccessed, \ 808 creationTime, \ 809 isSecure, \ 810 isHttpOnly, \ 811 inBrowserElement, \ 812 originAttributes, \ 813 sameSite, \ 814 schemeMap, \ 815 isPartitionedAttributeSet \ 816 ) VALUES ( \ 817 :name, \ 818 :value, \ 819 :host, \ 820 :path, \ 821 :expiry, \ 822 :lastAccessed, \ 823 :creationTime, \ 824 :isSecure, \ 825 :isHttpOnly, \ 826 :inBrowserElement, \ 827 :originAttributes, \ 828 :sameSite, \ 829 :schemeMap, \ 830 :isPartitionedAttributeSet)" 831 ); 832 833 this.stmtDelete = this.db.createStatement( 834 "DELETE FROM moz_cookies \ 835 WHERE name = :name AND host = :host AND path = :path AND \ 836 originAttributes = :originAttributes" 837 ); 838 839 this.stmtUpdate = this.db.createStatement( 840 "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ 841 WHERE name = :name AND host = :host AND path = :path AND \ 842 originAttributes = :originAttributes" 843 ); 844 845 break; 846 } 847 848 case 17: { 849 if (!exists) { 850 this.db.executeSimpleSQL( 851 "CREATE TABLE moz_cookies ( \ 852 id INTEGER PRIMARY KEY, \ 853 originAttributes TEXT NOT NULL DEFAULT '', \ 854 name TEXT, \ 855 value TEXT, \ 856 host TEXT, \ 857 path TEXT, \ 858 expiry INTEGER, \ 859 lastAccessed INTEGER, \ 860 creationTime INTEGER, \ 861 isSecure INTEGER, \ 862 isHttpOnly INTEGER, \ 863 inBrowserElement INTEGER DEFAULT 0, \ 864 sameSite INTEGER DEFAULT 0, \ 865 schemeMap INTEGER DEFAULT 0, \ 866 isPartitionedAttributeSet INTEGER DEFAULT 0, \ 867 updateTime INTEGER, \ 868 CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes))" 869 ); 870 871 this.db.executeSimpleSQL("PRAGMA journal_mode = WAL"); 872 this.db.executeSimpleSQL("PRAGMA wal_autocheckpoint = 16"); 873 } 874 875 this.stmtInsert = this.db.createStatement( 876 "INSERT INTO moz_cookies ( \ 877 name, \ 878 value, \ 879 host, \ 880 path, \ 881 expiry, \ 882 lastAccessed, \ 883 creationTime, \ 884 isSecure, \ 885 isHttpOnly, \ 886 inBrowserElement, \ 887 originAttributes, \ 888 sameSite, \ 889 schemeMap, \ 890 isPartitionedAttributeSet, \ 891 updateTime \ 892 ) VALUES ( \ 893 :name, \ 894 :value, \ 895 :host, \ 896 :path, \ 897 :expiry, \ 898 :lastAccessed, \ 899 :creationTime, \ 900 :isSecure, \ 901 :isHttpOnly, \ 902 :inBrowserElement, \ 903 :originAttributes, \ 904 :sameSite, \ 905 :schemeMap, \ 906 :isPartitionedAttributeSet, \ 907 :updateTime)" 908 ); 909 910 this.stmtDelete = this.db.createStatement( 911 "DELETE FROM moz_cookies \ 912 WHERE name = :name AND host = :host AND path = :path AND \ 913 originAttributes = :originAttributes" 914 ); 915 916 this.stmtUpdate = this.db.createStatement( 917 "UPDATE moz_cookies SET lastAccessed = :lastAccessed \ 918 WHERE name = :name AND host = :host AND path = :path AND \ 919 originAttributes = :originAttributes" 920 ); 921 922 break; 923 } 924 925 default: 926 do_throw("unrecognized schemaVersion!"); 927 } 928 } 929 930 CookieDatabaseConnection.prototype = { 931 insertCookie(cookie) { 932 if (!(cookie instanceof Cookie)) { 933 do_throw("not a cookie"); 934 } 935 936 switch (this.schema) { 937 case 1: 938 this.stmtInsert.bindByName("id", cookie.creationTime); 939 this.stmtInsert.bindByName("name", cookie.name); 940 this.stmtInsert.bindByName("value", cookie.value); 941 this.stmtInsert.bindByName("host", cookie.host); 942 this.stmtInsert.bindByName("path", cookie.path); 943 this.stmtInsert.bindByName("expiry", cookie.expiry); 944 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 945 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 946 break; 947 948 case 2: 949 this.stmtInsert.bindByName("id", cookie.creationTime); 950 this.stmtInsert.bindByName("name", cookie.name); 951 this.stmtInsert.bindByName("value", cookie.value); 952 this.stmtInsert.bindByName("host", cookie.host); 953 this.stmtInsert.bindByName("path", cookie.path); 954 this.stmtInsert.bindByName("expiry", cookie.expiry); 955 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 956 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 957 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 958 break; 959 960 case 3: 961 this.stmtInsert.bindByName("id", cookie.creationTime); 962 this.stmtInsert.bindByName("baseDomain", cookie.baseDomain); 963 this.stmtInsert.bindByName("name", cookie.name); 964 this.stmtInsert.bindByName("value", cookie.value); 965 this.stmtInsert.bindByName("host", cookie.host); 966 this.stmtInsert.bindByName("path", cookie.path); 967 this.stmtInsert.bindByName("expiry", cookie.expiry); 968 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 969 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 970 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 971 break; 972 973 case 4: 974 this.stmtInsert.bindByName("baseDomain", cookie.baseDomain); 975 this.stmtInsert.bindByName("name", cookie.name); 976 this.stmtInsert.bindByName("value", cookie.value); 977 this.stmtInsert.bindByName("host", cookie.host); 978 this.stmtInsert.bindByName("path", cookie.path); 979 this.stmtInsert.bindByName("expiry", cookie.expiry); 980 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 981 this.stmtInsert.bindByName("creationTime", cookie.creationTime); 982 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 983 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 984 break; 985 986 case 10: 987 this.stmtInsert.bindByName("name", cookie.name); 988 this.stmtInsert.bindByName("value", cookie.value); 989 this.stmtInsert.bindByName("host", cookie.host); 990 this.stmtInsert.bindByName("baseDomain", cookie.baseDomain); 991 this.stmtInsert.bindByName("path", cookie.path); 992 this.stmtInsert.bindByName("expiry", cookie.expiry); 993 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 994 this.stmtInsert.bindByName("creationTime", cookie.creationTime); 995 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 996 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 997 this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement); 998 this.stmtInsert.bindByName( 999 "originAttributes", 1000 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1001 ); 1002 this.stmtInsert.bindByName("sameSite", cookie.sameSite); 1003 this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite); 1004 break; 1005 1006 case 11: 1007 this.stmtInsert.bindByName("name", cookie.name); 1008 this.stmtInsert.bindByName("value", cookie.value); 1009 this.stmtInsert.bindByName("host", cookie.host); 1010 this.stmtInsert.bindByName("path", cookie.path); 1011 this.stmtInsert.bindByName("expiry", cookie.expiry); 1012 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 1013 this.stmtInsert.bindByName("creationTime", cookie.creationTime); 1014 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 1015 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 1016 this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement); 1017 this.stmtInsert.bindByName( 1018 "originAttributes", 1019 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1020 ); 1021 this.stmtInsert.bindByName("sameSite", cookie.sameSite); 1022 this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite); 1023 break; 1024 1025 case 12: 1026 this.stmtInsert.bindByName("name", cookie.name); 1027 this.stmtInsert.bindByName("value", cookie.value); 1028 this.stmtInsert.bindByName("host", cookie.host); 1029 this.stmtInsert.bindByName("path", cookie.path); 1030 this.stmtInsert.bindByName("expiry", cookie.expiry); 1031 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 1032 this.stmtInsert.bindByName("creationTime", cookie.creationTime); 1033 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 1034 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 1035 this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement); 1036 this.stmtInsert.bindByName( 1037 "originAttributes", 1038 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1039 ); 1040 this.stmtInsert.bindByName("sameSite", cookie.sameSite); 1041 this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite); 1042 this.stmtInsert.bindByName("schemeMap", cookie.schemeMap); 1043 break; 1044 1045 case 13: 1046 case 14: 1047 this.stmtInsert.bindByName("name", cookie.name); 1048 this.stmtInsert.bindByName("value", cookie.value); 1049 this.stmtInsert.bindByName("host", cookie.host); 1050 this.stmtInsert.bindByName("path", cookie.path); 1051 this.stmtInsert.bindByName("expiry", cookie.expiry); 1052 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 1053 this.stmtInsert.bindByName("creationTime", cookie.creationTime); 1054 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 1055 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 1056 this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement); 1057 this.stmtInsert.bindByName( 1058 "originAttributes", 1059 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1060 ); 1061 this.stmtInsert.bindByName("sameSite", cookie.sameSite); 1062 this.stmtInsert.bindByName("rawSameSite", cookie.rawSameSite); 1063 this.stmtInsert.bindByName("schemeMap", cookie.schemeMap); 1064 this.stmtInsert.bindByName( 1065 "isPartitionedAttributeSet", 1066 cookie.isPartitioned 1067 ); 1068 break; 1069 1070 case 15: 1071 case 16: 1072 this.stmtInsert.bindByName("name", cookie.name); 1073 this.stmtInsert.bindByName("value", cookie.value); 1074 this.stmtInsert.bindByName("host", cookie.host); 1075 this.stmtInsert.bindByName("path", cookie.path); 1076 this.stmtInsert.bindByName("expiry", cookie.expiry); 1077 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 1078 this.stmtInsert.bindByName("creationTime", cookie.creationTime); 1079 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 1080 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 1081 this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement); 1082 this.stmtInsert.bindByName( 1083 "originAttributes", 1084 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1085 ); 1086 this.stmtInsert.bindByName("sameSite", cookie.sameSite); 1087 this.stmtInsert.bindByName("schemeMap", cookie.schemeMap); 1088 this.stmtInsert.bindByName( 1089 "isPartitionedAttributeSet", 1090 cookie.isPartitioned 1091 ); 1092 break; 1093 1094 case 17: 1095 this.stmtInsert.bindByName("name", cookie.name); 1096 this.stmtInsert.bindByName("value", cookie.value); 1097 this.stmtInsert.bindByName("host", cookie.host); 1098 this.stmtInsert.bindByName("path", cookie.path); 1099 this.stmtInsert.bindByName("expiry", cookie.expiry); 1100 this.stmtInsert.bindByName("lastAccessed", cookie.lastAccessed); 1101 this.stmtInsert.bindByName("creationTime", cookie.creationTime); 1102 this.stmtInsert.bindByName("isSecure", cookie.isSecure); 1103 this.stmtInsert.bindByName("isHttpOnly", cookie.isHttpOnly); 1104 this.stmtInsert.bindByName("inBrowserElement", cookie.inBrowserElement); 1105 this.stmtInsert.bindByName( 1106 "originAttributes", 1107 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1108 ); 1109 this.stmtInsert.bindByName("sameSite", cookie.sameSite); 1110 this.stmtInsert.bindByName("schemeMap", cookie.schemeMap); 1111 this.stmtInsert.bindByName( 1112 "isPartitionedAttributeSet", 1113 cookie.isPartitioned 1114 ); 1115 this.stmtInsert.bindByName("updateTime", cookie.updateTime); 1116 break; 1117 1118 default: 1119 do_throw("unrecognized schemaVersion!"); 1120 } 1121 1122 do_execute_stmt(this.stmtInsert); 1123 }, 1124 1125 deleteCookie(cookie) { 1126 if (!(cookie instanceof Cookie)) { 1127 do_throw("not a cookie"); 1128 } 1129 1130 switch (this.db.schemaVersion) { 1131 case 1: 1132 case 2: 1133 case 3: 1134 this.stmtDelete.bindByName("id", cookie.creationTime); 1135 break; 1136 1137 case 4: 1138 this.stmtDelete.bindByName("name", cookie.name); 1139 this.stmtDelete.bindByName("host", cookie.host); 1140 this.stmtDelete.bindByName("path", cookie.path); 1141 break; 1142 1143 case 10: 1144 case 11: 1145 case 12: 1146 case 13: 1147 case 14: 1148 case 15: 1149 case 16: 1150 case 17: 1151 this.stmtDelete.bindByName("name", cookie.name); 1152 this.stmtDelete.bindByName("host", cookie.host); 1153 this.stmtDelete.bindByName("path", cookie.path); 1154 this.stmtDelete.bindByName( 1155 "originAttributes", 1156 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1157 ); 1158 break; 1159 1160 default: 1161 do_throw("unrecognized schemaVersion!"); 1162 } 1163 1164 do_execute_stmt(this.stmtDelete); 1165 }, 1166 1167 updateCookie(cookie) { 1168 if (!(cookie instanceof Cookie)) { 1169 do_throw("not a cookie"); 1170 } 1171 1172 switch (this.db.schemaVersion) { 1173 case 1: 1174 do_throw("can't update a schema 1 cookie!"); 1175 break; 1176 case 2: 1177 case 3: 1178 this.stmtUpdate.bindByName("id", cookie.creationTime); 1179 this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed); 1180 break; 1181 1182 case 4: 1183 this.stmtDelete.bindByName("name", cookie.name); 1184 this.stmtDelete.bindByName("host", cookie.host); 1185 this.stmtDelete.bindByName("path", cookie.path); 1186 this.stmtUpdate.bindByName("name", cookie.name); 1187 this.stmtUpdate.bindByName("host", cookie.host); 1188 this.stmtUpdate.bindByName("path", cookie.path); 1189 this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed); 1190 break; 1191 1192 case 10: 1193 case 11: 1194 case 12: 1195 case 13: 1196 case 14: 1197 case 15: 1198 case 16: 1199 case 17: 1200 this.stmtDelete.bindByName("name", cookie.name); 1201 this.stmtDelete.bindByName("host", cookie.host); 1202 this.stmtDelete.bindByName("path", cookie.path); 1203 this.stmtDelete.bindByName( 1204 "originAttributes", 1205 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1206 ); 1207 this.stmtUpdate.bindByName("name", cookie.name); 1208 this.stmtUpdate.bindByName("host", cookie.host); 1209 this.stmtUpdate.bindByName("path", cookie.path); 1210 this.stmtUpdate.bindByName( 1211 "originAttributes", 1212 ChromeUtils.originAttributesToSuffix(cookie.originAttributes) 1213 ); 1214 this.stmtUpdate.bindByName("lastAccessed", cookie.lastAccessed); 1215 break; 1216 1217 default: 1218 do_throw("unrecognized schemaVersion!"); 1219 } 1220 1221 do_execute_stmt(this.stmtUpdate); 1222 }, 1223 1224 close() { 1225 this.stmtInsert.finalize(); 1226 this.stmtDelete.finalize(); 1227 if (this.stmtUpdate) { 1228 this.stmtUpdate.finalize(); 1229 } 1230 this.db.close(); 1231 1232 this.stmtInsert = null; 1233 this.stmtDelete = null; 1234 this.stmtUpdate = null; 1235 this.db = null; 1236 }, 1237 }; 1238 1239 function do_get_cookie_file(profile) { 1240 let file = profile.clone(); 1241 file.append("cookies.sqlite"); 1242 return file; 1243 } 1244 1245 // Count the cookies from 'host' in a database. If 'host' is null, count all 1246 // cookies. 1247 function do_count_cookies_in_db(connection, host) { 1248 let select = null; 1249 if (host) { 1250 select = connection.createStatement( 1251 "SELECT COUNT(1) FROM moz_cookies WHERE host = :host" 1252 ); 1253 select.bindByName("host", host); 1254 } else { 1255 select = connection.createStatement("SELECT COUNT(1) FROM moz_cookies"); 1256 } 1257 1258 select.executeStep(); 1259 let result = select.getInt32(0); 1260 select.reset(); 1261 select.finalize(); 1262 return result; 1263 } 1264 1265 // Execute 'stmt', ensuring that we reset it if it throws. 1266 function do_execute_stmt(stmt) { 1267 try { 1268 stmt.executeStep(); 1269 stmt.reset(); 1270 } catch (e) { 1271 stmt.reset(); 1272 throw e; 1273 } 1274 }