Class: HTTPX::Plugins::Cookies::Jar

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/httpx/plugins/cookies/jar.rb

Overview

The Cookie Jar

It stores and manages cookies for a session, such as i.e. evicting when expired, access methods, or initialization from parsing Set-Cookie HTTP header values.

It closely follows the [CookieStore API](developer.mozilla.org/en-US/docs/Web/API/CookieStore), by implementing the same methods, with a few specific conveniences for this non-browser manipulation use-case.

Instance Method Summary collapse

Constructor Details

#initialize(cookies = nil) ⇒ Jar

initializes the cookie store, either empty, or with whatever is passed as cookies, which can be an array of HTTPX::Plugins::Cookies::Cookie objects or hashes-or-tuples of cookie attributes.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/httpx/plugins/cookies/jar.rb', line 26

def initialize(cookies = nil)
  @mtx = Thread::Mutex.new
  @cookies = []

  cookies.each do |elem|
    cookie = case elem
             when Cookie
               elem
             when Array
               Cookie.new(*elem)
             else
               Cookie.new(elem)
    end

    @cookies << cookie
  end if cookies
end

Instance Method Details

#[](uri) ⇒ Object

returns the list of valid cookies which matdh the domain and path from the URI object passed to uri.



116
117
118
# File 'lib/httpx/plugins/cookies/jar.rb', line 116

def [](uri)
  each(uri).sort
end

#add(cookie, path = nil) ⇒ Object

Deprecated.


93
94
95
96
97
98
# File 'lib/httpx/plugins/cookies/jar.rb', line 93

def add(cookie, path = nil)
  warn "DEPRECATION WARNING: calling `##{__method__}` is deprecated. Use `#set` instead."
  c = cookie.dup
  c.path = path if path && c.path == "/"
  set(c)
end

#delete(name_or_options) ⇒ Object

deletes all cookies in the store which match either the name (when String) or all attributes (when a Hash or array of tuples) passed to name_or_options.

alternatively, of name_or_options is an instance of HTTPX::Plugins::Cookies::Cookiem, it deletes it from the store.



104
105
106
107
108
109
110
111
112
113
# File 'lib/httpx/plugins/cookies/jar.rb', line 104

def delete(name_or_options)
  synchronize do
    case name_or_options
    when Cookie
      @cookies.delete(name_or_options)
    else
      @cookies.delete_if { |ck| ck.match?(name_or_options) }
    end
  end
end

#each(uri = nil, &blk) ⇒ Object

enumerates over all stored cookies. if uri is passed, it’ll filter out expired cookies and only yield cookies which match its domain and path.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/httpx/plugins/cookies/jar.rb', line 122

def each(uri = nil, &blk)
  return enum_for(__method__, uri) unless blk

  return synchronize { @cookies.each(&blk) } unless uri

  now = Time.now
  tpath = uri.path

  synchronize do
    @cookies.delete_if do |cookie|
      if cookie.expired?(now)
        true
      else
        yield cookie if cookie.valid_for_uri?(uri) && Cookie.path_match?(cookie.path, tpath)
        false
      end
    end
  end
end

#get(name_or_options) ⇒ Object

returns the first HTTPX::Plugins::Cookie::Cookie instance in the store which matches either the name (when String) or all attributes (when a Hash or array of tuples) passed to name_or_options



53
54
55
# File 'lib/httpx/plugins/cookies/jar.rb', line 53

def get(name_or_options)
  each.find { |ck| ck.match?(name_or_options) }
end

#get_all(name_or_options) ⇒ Object

returns all HTTPX::Plugins::Cookie::Cookie instances in the store which match either the name (when String) or all attributes (when a Hash or array of tuples) passed to name_or_options



59
60
61
# File 'lib/httpx/plugins/cookies/jar.rb', line 59

def get_all(name_or_options)
  each.select { |ck| ck.match?(name_or_options) } # rubocop:disable Style/SelectByRegexp
end

#initialize_dup(orig) ⇒ Object



18
19
20
21
22
# File 'lib/httpx/plugins/cookies/jar.rb', line 18

def initialize_dup(orig)
  super
  @mtx = orig.instance_variable_get(:@mtx).dup
  @cookies = orig.instance_variable_get(:@cookies).dup
end

#merge(other) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/httpx/plugins/cookies/jar.rb', line 142

def merge(other)
  jar_dup = dup

  other.each do |elem|
    cookie = case elem
             when Cookie
               elem
             when Array
               Cookie.new(*elem)
             else
               Cookie.new(elem)
    end

    jar_dup.set(cookie)
  end

  jar_dup
end

#parse(set_cookie) ⇒ Object

parses the Set-Cookie header value as set_cookie and does the corresponding updates.



45
46
47
48
49
# File 'lib/httpx/plugins/cookies/jar.rb', line 45

def parse(set_cookie)
  SetCookieParser.call(set_cookie) do |name, value, attrs|
    set(Cookie.new(name, value, attrs))
  end
end

#set(name, value_or_options = nil) ⇒ Object

optionally, name can also be the attributes hash-or-array as long it contains a :name field).



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/httpx/plugins/cookies/jar.rb', line 67

def set(name, value_or_options = nil)
  cookie = case name
           when Cookie
             raise ArgumentError, "there should not be a second argument" if value_or_options

             name
           when Array, Hash
             raise ArgumentError, "there should not be a second argument" if value_or_options

             Cookie.new(name)
           else
             raise ArgumentError, "the second argument is required" unless value_or_options

             Cookie.new(name, value_or_options)
  end

  synchronize do
    # If the user agent receives a new cookie with the same cookie-name, domain-value, and path-value
    # as a cookie that it has already stored, the existing cookie is evicted and replaced with the new cookie.
    @cookies.delete_if { |ck| ck.name == cookie.name && ck.domain == cookie.domain && ck.path == cookie.path }

    @cookies << cookie
  end
end