Skip to content

Instantly share code, notes, and snippets.

@ishiduca
Last active August 29, 2015 14:23
Show Gist options
  • Save ishiduca/4e2d58054d64dd6a90b4 to your computer and use it in GitHub Desktop.
Save ishiduca/4e2d58054d64dd6a90b4 to your computer and use it in GitHub Desktop.
a cookie manager for HTTP client
'use strict'
var qs = require('querystring')
var url = require('url')
var merge = require('deepmerge')
var hyperquest = require('hyperquest')
var trumpet = require('trumpet')
var cookiepass = require('../index')
var auth = require('./auth')
var login = 'https://www.secure.pixiv.net/login.php'
var home = 'http://www.pixiv.net'
var illust = home + '/bookmark_new_illust.php'
var tr = trumpet()
var selector = '#wrapper>div.layout-body>div._unit>ul>li.image-item'
tr.selectAll(selector, function (li) {
var tr = trumpet()
var data = {}
tr.select('a>h1.title', function (h1) {
h1.getAttribute('title', function (title) {
data.title = title
done()
})
})
tr.select('a.user', function (a) {
a.getAttribute('title', function (title) {
data.user = title
done()
})
})
li.createReadStream().pipe(tr)
function done () {
Object.keys(data).length === 2 && console.dir(data)
}
})
var body = qs.stringify(merge(auth, {
mode: 'login', skip: 1
}))
var cookie = cookiepass(login)
var opt = {
headers: {
'content-type': 'application/x-www-form-urlencoded'
, 'content-length': Buffer.byteLength(body)
}
}
var req = hyperquest.post(login, opt)
.once('error', console.error.bind(console))
.once('response', function (res) {
if (/^3/.test(res.statusCode) && res.headers.location) {
var opt = url.parse(res.headers.location)
cookie(res)(opt)
hyperquest(res.headers.location, opt)
.once('error', console.error.bind(console))
.once('response', function (res) {
var cookieStr = cookie(res)(illust)
hyperquest(illust, {headers: {cookie: cookieStr}})
.once('error', console.error.bind(console))
.pipe(tr)
})
}
})
req.end(body)
'use strict'
var url = require('url')
var deepmerge = require('deepmerge')
var parse = require('./lib/parse')
var stringify = require('./lib/stringify')
module.exports = function cookiepass (req) {
var jar = {}
return function merge (res) {
jar = deepmerge(jar, parse(res, req))
return function pass (_req) {
req = typeof _req === 'string' ? url.parse(_req) : _req
return ((req.headers || (req.headers = {})).cookie = stringify(jar, req))
}
}
}
'use strict'
module.exports = function parseLine (str) {
var cookies = str.split(/;\s*/)
var kv = cookies.shift()
var first = kv.split('=')
var cookiesMap = cookies.reduce(function (cookie, str) {
var pair = str.split('=')
var key = pair[0].trim()
var val = typeof pair[1] === 'undefined' ? true : pair[1]
if (typeof val === 'string') val = val.trim()
if (key.toLowerCase() === 'max-age' && ! isNaN(val)) {
cookie._expires = Date.now() + Number(val)
}
cookie[key] = val
return cookie
}, {key: first[0].trim(), val: first[1].trim()})
if (cookiesMap.expires && ! cookiesMap._expires)
cookiesMap._expires = Date.parse(cookiesMap.expires)
return cookiesMap
}
'use strict'
var url = require('url')
var merge = require('deepmerge')
var parseLine = require('./parse-line')
module.exports = function parseSetCookie (res, _req) {
if (arguments.length !== 2)
throw new Error('usage: parseSetCookie(response, request)')
var req = (typeof _req === 'string') ? url.parse(_req) : _req
var jar = {cookies: {}, cookiesStrict: {}}
var hostname = req.hostname || req.host.split(':')[0]
var setCookie = (res.headers || {})['set-cookie']
if (! setCookie) return jar
if (typeof setCookie === 'string') setCookie = [setCookie]
return setCookie.reduce(function (jar, str) {
var cookie = parseLine(str)
var mode = (!! cookie.domain) ? 'cookies' : 'cookiesStrict'
var domain = cookie.domain || hostname
var path = (cookie.path && cookie.path.slice(0, 1) === '/')
? cookie.path : '/'
var id = cookie.key
var pot = {}
pot[mode] = {}
pot[mode][domain] = {}
pot[mode][domain][path] = {}
pot[mode][domain][path][id] = cookie
return merge(jar, pot)
}, jar)
}
'use strict'
var url = require('url')
function flatmap (arry, f) {
return arry.reduce(function (arry, val) {
return arry.concat(f(val))
}, [])
}
module.exports = function stringify (jar, req) {
if (arguments.length !== 2)
throw new Error('usage: stringify(jar, requestOption)')
if (typeof req === 'string')
throw new TypeError('2nd argument must be "URLObject"')
var now = Date.now()
var hostname = req.hostname || req.host.split(':')[0]
var path = req.pathname || req.path.split('?')[0]
var cookies = (req.headers || (req.headers = {})).cookie || []
if (typeof cookies === 'string') cookies = cookies.split(/[;,]\s*/)
var a = flatmap(
Object.keys(jar.cookies).filter(function (domain) {
var _domain = domain.slice(0, 1) === '.'
? domain.slice(1) : domain
return _domain === hostname.slice(-_domain.length) &&
(_domain === hostname ||
'.' + _domain === hostname.slice(-(_domain.length + 1)))
})
, function (domain) {
return help(jar.cookies[domain])
}
)
var b = flatmap(
Object.keys(jar.cookiesStrict).filter(function (domain) {
return domain === hostname
})
, function (domain) {
return help(jar.cookiesStrict[domain])
}
)
return cookies.concat(a).concat(b).join('; ')
function help (c) {
return flatmap(
Object.keys(c).filter(pathFilter)
, function (_path) {
return Object.keys(c[_path]).filter(function (id) {
return c[_path][id] !== null
}).filter(function (id) {
var _expires = c[_path][id]._expires
if (now > _expires) {
c[_path][id] = null
return false
}
return true
}).map(function (id) {
return [id, c[_path][id].val].join('=')
})
}
)
function pathFilter (_path) {
return path.slice(0, _path.length) === _path
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment