Files: ab2db5816540d4eaf2e71a3d8b00a0b297c3da74 / index.js
2896 bytesRaw
1 | var pull = require('pull-stream') |
2 | var toPull = require('stream-to-pull-stream') |
3 | |
4 | var qs = require('querystring') |
5 | var URL = require('url') |
6 | |
7 | var YEAR = 60*60*24*365 |
8 | |
9 | function headers(res, hash) { |
10 | //don't set cache control because (i think) that tells |
11 | //the browser to not keep the cache |
12 | res.setHeader('cache-control', 'maxage='+YEAR) |
13 | //expires makes the brower not even revalidate. |
14 | res.setHeader('expires', new Date(Date.now()+YEAR*1000).toISOString()) |
15 | res.setHeader('expiry', new Date(Date.now()+YEAR*1000).toISOString()) |
16 | res.setHeader('etag', hash) |
17 | } |
18 | |
19 | //host blobs |
20 | module.exports = function (blobs, url, opts) { |
21 | opts = opts || {} |
22 | return function (req, res, next) { |
23 | |
24 | next = next || function (err) { |
25 | res.writeHead(404, {'Content-Type': 'application/json'}) |
26 | res.end(JSON.stringify({error: true, status: 404})) |
27 | } |
28 | |
29 | if(req.method === 'POST' && req.url === url+'/add' && opts.readonly !== true) |
30 | pull( |
31 | toPull(req), |
32 | blobs.add(function (err, hash) { |
33 | res.end(hash) |
34 | }) |
35 | ) |
36 | else if(req.url.indexOf(url+'/get/') == 0) { |
37 | if(!(req.method === "GET" || req.method == 'HEAD')) return next() |
38 | |
39 | var u = URL.parse('http://makeurlparseright.com'+req.url) |
40 | var hash = decodeURIComponent(u.pathname.substring((url+'/get/').length)) |
41 | var q = qs.parse(u.query) |
42 | |
43 | |
44 | //if a browser revalidates, just tell them it hasn't changed, the hash has not changed. |
45 | if(req.headers['if-none-match'] === hash) { |
46 | headers(res, hash) |
47 | return res.writeHead(304), res.end() |
48 | } |
49 | |
50 | //enable cors by default |
51 | if(opts.cors !== false) { |
52 | res.setHeader('Access-Control-Allow-Origin', '*') |
53 | } |
54 | |
55 | // prevent timeout while waiting for blob |
56 | res.setTimeout(0) |
57 | |
58 | blobs.size(hash, function (err, size) { |
59 | if(err) return next(err) |
60 | if(!size) return next(new Error('no blob:'+hash)) |
61 | |
62 | headers(res, hash) |
63 | res.setHeader('content-length', size) |
64 | |
65 | if(q.filename) |
66 | res.setHeader('Content-Discosition', 'inline; filename='+q.filename) |
67 | |
68 | if(q.gzip) |
69 | res.setHeader('Content-Encoding', 'gzip') |
70 | |
71 | if(q.contentType) |
72 | res.setHeader('Content-Type', q.contentType) |
73 | |
74 | //writing the status code now. |
75 | res.writeHead(200) |
76 | if(req.method === 'HEAD') return res.end() |
77 | |
78 | pull( |
79 | blobs.get(hash), |
80 | //since this is an http stream, handle error the http way. |
81 | //there is nothing we can do about an error now, since |
82 | //we already wrote the headers. but since we included content-length |
83 | //the client will know it went wrong. |
84 | // pull.through(null, function (err) { |
85 | // if(err) throw err //DEBUG |
86 | // if(err) next(err) |
87 | // }), |
88 | toPull(res) |
89 | ) |
90 | }) |
91 | } |
92 | else next() |
93 | } |
94 | } |
95 | |
96 | |
97 | |
98 | |
99 | |
100 | |
101 | |
102 | |
103 | |
104 | |
105 | |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 |
Built with git-ssb-web