Skip to content

Commit 2f75741

Browse files
committed
兼容 IPV6 域名,支持自动调正签名时间
1 parent a613fbd commit 2f75741

File tree

8 files changed

+120
-71
lines changed

8 files changed

+120
-71
lines changed

demo/demo-sts.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ var policy = {
2323
'effect': 'allow',
2424
'principal': {'qcs': ['*']},
2525
'resource': [
26-
'qcs::cos:ap-guangzhou:uid/' + AppId + ':prefix//' + AppId + '/' + ShortBucketName + '/dir/*'
26+
'qcs::cos:' + config.Region + ':uid/' + AppId + ':prefix//' + AppId + '/' + ShortBucketName + '/*'
2727
]
2828
}]
2929
};
@@ -45,6 +45,7 @@ var cos = new COS({
4545
TmpSecretId: credentials.tmpSecretId,
4646
TmpSecretKey: credentials.tmpSecretKey,
4747
XCosSecurityToken: credentials.sessionToken,
48+
StartTime: data.starteTime,
4849
ExpiredTime: data.expiredTime,
4950
});
5051
}

demo/demo.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ function deleteBucket() {
448448
console.log(err || data);
449449
});
450450
}
451-
return putObject();
451+
452452
function putObject() {
453453
// 创建测试文件
454454
var filename = '1mb.zip';

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cos-nodejs-sdk-v5",
3-
"version": "2.5.3",
3+
"version": "2.5.4",
44
"description": "cos nodejs sdk v5",
55
"main": "index.js",
66
"scripts": {
@@ -34,6 +34,6 @@
3434
},
3535
"devDependencies": {
3636
"mocha": "^4.0.1",
37-
"qcloud-cos-sts": "^2.0.5"
37+
"qcloud-cos-sts": "^2.0.6"
3838
}
3939
}

sdk/advance.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -961,15 +961,15 @@ function sliceCopyFile(params, callback) {
961961
var Region = params.Region;
962962
var Key = params.Key;
963963
var CopySource = params.CopySource;
964-
var m = CopySource.match(/^([^.]+-\d+)\.cos\.([^.]+)\.[^/]+\/(.+)$/);
964+
var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/);
965965
if (!m) {
966966
callback({error: 'CopySource format error'});
967967
return;
968968
}
969969

970970
var SourceBucket = m[1];
971-
var SourceRegion = m[2];
972-
var SourceKey = decodeURIComponent(m[3]);
971+
var SourceRegion = m[3];
972+
var SourceKey = decodeURIComponent(m[4]);
973973
var CopySliceSize = params.SliceSize === undefined ? self.options.CopySliceSize : params.SliceSize;
974974
CopySliceSize = Math.max(0, Math.min(CopySliceSize, 5 * 1024 * 1024 * 1024));
975975

sdk/base.js

Lines changed: 83 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,15 +1406,15 @@ function optionsObject(params, callback) {
14061406
*/
14071407
function putObjectCopy(params, callback) {
14081408
var CopySource = params.CopySource || '';
1409-
var m = CopySource.match(/^([^.]+-\d+)\.cos\.([^.]+)\.[^/]+\/(.+)$/);
1409+
var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/);
14101410
if (!m) {
14111411
callback({error: 'CopySource format error'});
14121412
return;
14131413
}
14141414

14151415
var SourceBucket = m[1];
1416-
var SourceRegion = m[2];
1417-
var SourceKey = decodeURIComponent(m[3]);
1416+
var SourceRegion = m[3];
1417+
var SourceKey = decodeURIComponent(m[4]);
14181418

14191419
submitRequest.call(this, {
14201420
Scope: [{
@@ -1450,15 +1450,15 @@ function putObjectCopy(params, callback) {
14501450
function uploadPartCopy(params, callback) {
14511451

14521452
var CopySource = params.CopySource || '';
1453-
var m = CopySource.match(/^([^.]+-\d+)\.cos\.([^.]+)\.[^/]+\/(.+)$/);
1453+
var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/);
14541454
if (!m) {
14551455
callback({error: 'CopySource format error'});
14561456
return;
14571457
}
14581458

14591459
var SourceBucket = m[1];
1460-
var SourceRegion = m[2];
1461-
var SourceKey = decodeURIComponent(m[3]);
1460+
var SourceRegion = m[3];
1461+
var SourceKey = decodeURIComponent(m[4]);
14621462

14631463
submitRequest.call(this, {
14641464
Scope: [{
@@ -1909,6 +1909,7 @@ function getAuth(params) {
19091909
Headers: params.Headers,
19101910
Expires: params.Expires,
19111911
UseRawKey: self.options.UseRawKey,
1912+
SystemClockOffset: self.options.SystemClockOffset,
19121913
});
19131914
}
19141915

@@ -2163,7 +2164,7 @@ function getAuthorizationAsync(params, callback) {
21632164
var i, AuthData;
21642165
for (i = self._StsCache.length - 1; i >= 0; i--) {
21652166
AuthData = self._StsCache[i];
2166-
if (AuthData.ExpiredTime < Math.round(Date.now() / 1000) + 10) {
2167+
if (AuthData.ExpiredTime < Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30) {
21672168
self._StsCache.splice(i, 1);
21682169
continue;
21692170
}
@@ -2183,6 +2184,7 @@ function getAuthorizationAsync(params, callback) {
21832184
Query: params.Query,
21842185
Headers: params.Headers,
21852186
UseRawKey: self.options.UseRawKey,
2187+
SystemClockOffset: self.options.SystemClockOffset,
21862188
});
21872189
var AuthData = {
21882190
Authorization: Authorization,
@@ -2195,7 +2197,7 @@ function getAuthorizationAsync(params, callback) {
21952197
};
21962198

21972199
// 先判断是否有临时密钥
2198-
if (StsData.ExpiredTime && StsData.ExpiredTime - (Date.now() / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用
2200+
if (StsData.ExpiredTime && StsData.ExpiredTime - (util.getSkewTime(self.options.SystemClockOffset) / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用
21992201
calcAuthByTmpKey();
22002202
} else if (self.options.getAuthorization) { // 外部计算签名或获取临时密钥
22012203
self.options.getAuthorization.call(self, {
@@ -2247,6 +2249,7 @@ function getAuthorizationAsync(params, callback) {
22472249
Headers: params.Headers,
22482250
Expires: params.Expires,
22492251
UseRawKey: self.options.UseRawKey,
2252+
SystemClockOffset: self.options.SystemClockOffset,
22502253
});
22512254
var AuthData = {
22522255
Authorization: Authorization,
@@ -2259,6 +2262,35 @@ function getAuthorizationAsync(params, callback) {
22592262
return '';
22602263
}
22612264

2265+
// 调整时间偏差
2266+
function allowRetry(err) {
2267+
var allowRetry = false;
2268+
var isTimeError = false;
2269+
var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || '';
2270+
try {
2271+
var errorCode = err.error.Code;
2272+
var errorMessage = err.error.Message;
2273+
if (errorCode === 'RequestTimeTooSkewed' ||
2274+
(errorCode === 'AccessDenied' && errorMessage === 'Request has expired')) {
2275+
isTimeError = true;
2276+
}
2277+
} catch (e) {
2278+
}
2279+
if (err) {
2280+
if (isTimeError && serverDate) {
2281+
var serverTime = Date.parse(serverDate);
2282+
if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) {
2283+
console.error('error: Local time is too skewed.');
2284+
this.options.SystemClockOffset = serverTime - Date.now();
2285+
allowRetry = true;
2286+
}
2287+
} else if (Math.round(err.statusCode / 100) === 5) {
2288+
allowRetry = true;
2289+
}
2290+
}
2291+
return allowRetry;
2292+
}
2293+
22622294
// 获取签名并发起请求
22632295
function submitRequest(params, callback) {
22642296
var self = this;
@@ -2278,51 +2310,39 @@ function submitRequest(params, callback) {
22782310

22792311
var Query = util.clone(params.qs);
22802312
params.action && (Query[params.action] = '');
2281-
getAuthorizationAsync.call(self, {
2282-
Bucket: params.Bucket || '',
2283-
Region: params.Region || '',
2284-
Method: params.method,
2285-
Key: params.Key,
2286-
Query: Query,
2287-
Headers: params.headers,
2288-
Action: params.Action,
2289-
ResourceKey: params.ResourceKey,
2290-
Scope: params.Scope,
2291-
}, function (err, AuthData) {
22922313

2293-
// 检查签名格式
2294-
var auth = AuthData.Authorization;
2295-
var formatAllow = false;
2296-
if (auth) {
2297-
if (auth.indexOf(' ') > -1) {
2298-
formatAllow = false;
2299-
} else if (auth.indexOf('q-sign-algorithm=') > -1 &&
2300-
auth.indexOf('q-ak=') > -1 &&
2301-
auth.indexOf('q-sign-time=') > -1 &&
2302-
auth.indexOf('q-key-time=') > -1 &&
2303-
auth.indexOf('q-url-param-list=') > -1) {
2304-
formatAllow = true;
2305-
} else {
2306-
try {
2307-
auth = atob(auth);
2308-
if (auth.indexOf('a=') > -1 &&
2309-
auth.indexOf('k=') > -1 &&
2310-
auth.indexOf('t=') > -1 &&
2311-
auth.indexOf('r=') > -1 &&
2312-
auth.indexOf('b=') > -1) {
2313-
formatAllow = true;
2314+
var next = function (tryIndex) {
2315+
var oldClockOffset = self.options.SystemClockOffset;
2316+
getAuthorizationAsync.call(self, {
2317+
Bucket: params.Bucket || '',
2318+
Region: params.Region || '',
2319+
Method: params.method,
2320+
Key: params.Key,
2321+
Query: Query,
2322+
Headers: params.headers,
2323+
Action: params.Action,
2324+
ResourceKey: params.ResourceKey,
2325+
Scope: params.Scope,
2326+
}, function (err, AuthData) {
2327+
params.AuthData = AuthData;
2328+
_submitRequest.call(self, params, function (err, data) {
2329+
if (err && tryIndex < 2 && (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) {
2330+
if (params.headers) {
2331+
delete params.headers.Authorization;
2332+
delete params.headers['token'];
2333+
delete params.headers['clientIP'];
2334+
delete params.headers['clientUA'];
2335+
delete params.headers['x-cos-security-token'];
23142336
}
2315-
} catch (e) {}
2316-
}
2317-
}
2318-
if (!formatAllow) {
2319-
callback('authorization error');
2320-
return;
2321-
}
2337+
next(tryIndex + 1);
2338+
} else {
2339+
callback(err, data);
2340+
}
2341+
});
2342+
});
2343+
};
2344+
next(0);
23222345

2323-
params.AuthData = AuthData;
2324-
_submitRequest.call(self, params, callback);
2325-
});
23262346
}
23272347

23282348
// 发起请求
@@ -2415,6 +2435,10 @@ function _submitRequest(params, callback) {
24152435
data = util.extend(data || {}, attrs);
24162436
callback(null, data);
24172437
}
2438+
if (sender) {
2439+
sender.removeAllListeners && sender.removeAllListeners();
2440+
sender = null;
2441+
}
24182442
};
24192443
var xml2json = function (body) {
24202444
try {
@@ -2440,10 +2464,10 @@ function _submitRequest(params, callback) {
24402464
} else if (responseContentLength >= process.binding('buffer').kMaxLength && opt.method !== 'HEAD') {
24412465
cb({error: 'file size large than ' + process.binding('buffer').kMaxLength + ', please use "Output" Stream to getObject.'});
24422466
} else {
2443-
sender.on('data', function (chunk) {
2467+
var dataHandler = function (chunk) {
24442468
chunkList.push(chunk);
2445-
});
2446-
sender.on('end', function () {
2469+
};
2470+
var endHandler = function () {
24472471
var json;
24482472
try {
24492473
var body = Buffer.concat(chunkList);
@@ -2469,7 +2493,10 @@ function _submitRequest(params, callback) {
24692493
bodyStr && (json = xml2json(bodyStr));
24702494
cb({error: json && json.Error || response.statusMessage || 'statusCode error'});
24712495
}
2472-
});
2496+
chunkList = null;
2497+
};
2498+
sender.on('data', dataHandler);
2499+
sender.on('end', endHandler);
24732500
}
24742501
});
24752502

@@ -2535,15 +2562,15 @@ function _submitRequest(params, callback) {
25352562
// pipe 输入
25362563
if (readStream) {
25372564
readStream.on('error', function (err) {
2538-
sender.abort();
2565+
sender && sender.abort && sender.abort();
25392566
callback(err);
25402567
});
25412568
readStream.pipe(sender);
25422569
}
25432570
// pipe 输出
25442571
if (params.outputStream) {
25452572
params.outputStream.on('error', function (err) {
2546-
sender.abort();
2573+
sender && sender.abort && sender.abort();
25472574
callback(err)
25482575
});
25492576
sender.pipe(params.outputStream);

sdk/cos.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ var defaultOptions = {
3030
ForcePathStyle: false,
3131
UseRawKey: false,
3232
Timeout: 0, // 单位毫秒,0 代表不设置超时时间
33+
CorrectClockSkew: true,
34+
SystemClockOffset: 0, // 单位毫秒,ms
3335
UploadCheckContentMd5: false,
3436
UploadIdCacheLimit: 500,
3537
Proxy: '',

sdk/task.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ var initTask = function (cos) {
4444
cos.emit('list-update', {list: util.map(queue, formatTask)});
4545
};
4646

47+
var clearQueue = function () {
48+
if (queue.length > cos.options.UploadQueueSize) {
49+
var i;
50+
for (i = 0;
51+
i < queue.length &&
52+
queue.length > cos.options.UploadQueueSize && // 大于队列才处理
53+
i < nextUploadIndex; // 小于当前操作的 index 才处理
54+
i++) {
55+
if (!queue[i] || queue[i].state !== 'waiting') {
56+
console.log('splice:', queue.length, i, queue[i] && queue[i].state);
57+
queue.splice(i, 1);
58+
nextUploadIndex--;
59+
}
60+
}
61+
}
62+
};
63+
4764
var startNextTask = function () {
4865
if (nextUploadIndex < queue.length &&
4966
uploadingFileCount < cos.options.FileParallelLimit) {
@@ -69,6 +86,7 @@ var initTask = function (cos) {
6986
delete task.callback;
7087
}
7188
}
89+
clearQueue();
7290
});
7391
emitListUpdate();
7492
}
@@ -170,14 +188,10 @@ var initTask = function (cos) {
170188
// 获取完文件大小再把任务加入队列
171189
tasks[id] = task;
172190
queue.push(task);
173-
if (queue.length > cos.options.UploadQueueSize) {
174-
var delta = queue.length - cos.options.UploadQueueSize;
175-
queue.splice(0, delta);
176-
nextUploadIndex -= delta;
177-
}
178191
task.size = size;
179192
!ignoreAddEvent && emitListUpdate();
180193
startNextTask(cos);
194+
clearQueue();
181195
});
182196
return id;
183197
};

0 commit comments

Comments
 (0)