Skip to content

Commit bb40572

Browse files
committed
Implemeted basic random access read method
1 parent f1c5a06 commit bb40572

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed

index.js

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ var http = require('http')
44
var https = require('https')
55
var url = require('url')
66
var xtend = require('xtend')
7+
var concat = require('concat-stream')
8+
var pump = require('pump')
9+
var limitStream = require('size-limit-stream')
710

811
module.exports = RandomAccessHTTP
912

@@ -35,16 +38,18 @@ RandomAccessHTTP.prototype.open = function (cb) {
3538
Connection: 'keep-alive'
3639
}
3740
})
38-
var req = this.client.request(reqOpts, function (res) {
41+
var req = this.client.request(reqOpts, onres)
42+
43+
function onres (res) {
3944
if (res.statusCode !== 200) return cb(new Error('Bad response: ' + res.statusCode))
4045
if (headersInvalid(res.headers)) {
41-
return cb(new Error("Source doesn' support 'accept-ranges'"))
46+
return cb(new Error("Source doesn't support 'accept-ranges'"))
4247
}
4348
self.opened = true
4449
if (res.headers['content-length']) self.length = res.headers['content-length']
4550
self.emit('open')
4651
cb()
47-
})
52+
}
4853

4954
req.on('error', (e) => {
5055
return cb(new Error(`problem with request: ${e.message}`))
@@ -70,22 +75,57 @@ RandomAccessHTTP.prototype.read = function (offset, length, cb) {
7075
if (!this.readable) return cb(new Error('File is not readable'))
7176

7277
var self = this
78+
7379
var buf = Buffer(length)
7480

7581
if (!length) return cb(null, buf)
7682
var reqOpts = xtend(this.urlObj, {
7783
method: 'HEAD',
7884
headers: {
7985
Connection: 'keep-alive',
80-
'Accept-Ranges': 'bytes'
86+
Range: `bytes=${offset}-${offset + length}`
8187
}
8288
})
8389

84-
function onres () {
85-
// todo
90+
var req = this.client.request(reqOpts, onres)
91+
92+
req.on('error', (e) => {
93+
return cb(new Error(`problem with read request: ${e.message}`))
94+
})
95+
96+
req.end()
97+
98+
function onres (res) {
99+
if (res.statusCode !== 206) return cb(new Error('Bad response: ' + res.statusCode))
100+
if (!res.headers['content-range']) return cb(new Error('Server did not return a byte range'))
101+
var expectedRange = `bytes ${offset}-${offset + length}/${self.length}`
102+
if (res.headers['content-range'] !== expectedRange) return cb(new Error('Server returned unexpected range: ' + res.headers['content-range']))
103+
var limiter = limitStream(length)
104+
var concatStream = concat(onBuf)
105+
106+
pump(res, limiter, concatStream, function (err) {
107+
if (err) return cb(new Error(`problem while reading stream: ${err}`))
108+
})
109+
}
110+
111+
function onBuf (buf) {
112+
return cb(null, buf)
86113
}
87114
}
88115

116+
// function parseRangeHeader (rangeHeader) {
117+
// var range = {}
118+
// var byteRangeArr = rangeHeader.split(' ')
119+
// range.unit = byteRangeArr[0]
120+
// var ranges = byteRangeArr[1].split('/')
121+
// range.totalLength = ranges[1]
122+
// var startStop = ranges[0].split('-')
123+
// range.offset = startStop[0]
124+
// range.end = startStop[1]
125+
// range.length = range.end - range.offset
126+
// return range
127+
// }
128+
89129
RandomAccessHTTP.prototype.close = function (cb) {
90130
this.opened = false
91131
this.emit('close')

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
"dependencies": {
2323
"inherits": "^2.0.1",
2424
"mkdirp": "^0.5.1",
25+
"pump": "^1.0.1",
26+
"size-limit-stream": "^1.0.0",
2527
"thunky": "^0.1.0",
2628
"xtend": "^4.0.1"
2729
},

test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,14 @@ tape('open and close', function (t) {
1919
})
2020
})
2121
})
22+
23+
tape('read 10 bytes', function (t) {
24+
t.plan(2)
25+
var popeye = rahttp(testUrl)
26+
popeye.read(0, 10, function (err) {
27+
t.error(err, 'url read without error')
28+
popeye.close(function (err) {
29+
t.error(err, 'url closed without error')
30+
})
31+
})
32+
})

0 commit comments

Comments
 (0)