pub struct UploadPolicy { /* private fields */ }
Expand description

上传策略

可以阅读 https://developer.qiniu.com/kodo/manual/1206/put-policy 了解七牛安全机制。

根据指定的存储空间和对象名称,生成可以用来上传低频存储类型文件的上传策略

use qiniu_upload_token::{FileType, UploadPolicy};
use std::time::Duration;

let upload_policy = UploadPolicy::new_for_object("your-bucket", "your-key", Duration::from_secs(3600))
    .file_type(FileType::InfrequentAccess)
    .build();

Implementations§

为指定的存储空间生成的上传策略

允许用户上传文件到指定的存储空间,不限制上传客户端指定对象名称。

上传策略根据给出的客户端配置指定上传凭证有效期

为指定的存储空间和对象名称生成的上传策略

允许用户以指定的对象名称上传文件到指定的存储空间。 上传客户端不能指定与上传策略冲突的对象名称。

上传策略根据给出的客户端配置指定上传凭证有效期

为指定的存储空间和对象名称前缀生成的上传策略

允许用户以指定的对象名称前缀上传文件到指定的存储空间。 上传客户端指定包含该前缀的对象名称。

上传策略根据给出的客户端配置指定上传凭证有效期

存储空间约束

Examples found in repository?
src/upload_token.rs (line 233)
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
    fn bucket_name(&self, opts: GetPolicyOptions) -> ParseResult<BucketName> {
        self.policy(opts).and_then(|policy| {
            policy
                .bucket()
                .map_or(Err(ParseError::InvalidUploadTokenFormat), |bucket_name| {
                    Ok(BucketName::from(bucket_name))
                })
        })
    }

    /// 异步获取上传凭证中的存储空间名称
    #[cfg(feature = "async")]
    #[cfg_attr(feature = "docs", doc(cfg(feature = "async")))]
    fn async_bucket_name(&self, opts: GetPolicyOptions) -> AsyncParseResult<'_, BucketName> {
        Box::pin(async move {
            self.async_policy(opts).await.and_then(|policy| {
                policy
                    .bucket()
                    .map_or(Err(ParseError::InvalidUploadTokenFormat), |bucket_name| {
                        Ok(BucketName::from(bucket_name))
                    })
            })
        })
    }

对象名称约束或对象名称前缀约束

是否是对象名称前缀约束

是否仅允许新增对象,不允许覆盖对象

是否启用 MIME 类型自动检测

上传凭证过期时间

Web 端文件上传成功后,浏览器执行 303 跳转的 URL

上传成功后,自定义七牛云最终返回给上传端的数据

上传成功后,七牛云向业务服务器发送 POST 请求的 URL 列表

上传成功后,七牛云向业务服务器发送回调请求时的 Host

上传成功后,七牛云向业务服务器发送回调请求时的内容

支持魔法变量自定义变量

上传成功后,七牛云向业务服务器发送回调请求时的 Content-Type

默认为 application/x-www-form-urlencoded,也可设置为 application/json

自定义对象名称

支持魔法变量自定义变量

是否忽略客户端指定的对象名称,强制使用自定义对象名称进行文件命名

限定上传文件尺寸的范围

返回的第一个元素为最小尺寸,第二个元素为最大尺寸,如果为 None 表示不限制,单位为字节

限定用户上传的文件类型

指定本字段值,七牛服务器会侦测文件内容以判断 MIME 类型,再用判断值跟指定值进行匹配, 匹配成功则允许上传,匹配失败则返回 403 状态码

文件类型

对象生命周期

精确到天

获取 JSON 格式的上传凭证

Examples found in repository?
src/upload_token.rs (line 406)
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
    fn to_token_string(&self, _opts: ToStringOptions) -> ToStringResult<Cow<'_, str>> {
        Ok(Cow::Owned(
            self.credential
                .get(Default::default())?
                .sign_with_data(self.upload_policy.as_json().as_bytes()),
        ))
    }
}

type OnPolicyGeneratedCallback = Arc<dyn Fn(&mut UploadPolicyBuilder) -> AnyResult<()> + Sync + Send + 'static>;

/// 基于存储空间的动态生成
///
/// 根据存储空间的快速生成上传凭证实例
#[derive(Clone)]
pub struct BucketUploadTokenProvider<C: Clone> {
    bucket: BucketName,
    upload_token_lifetime: Duration,
    credential: C,
    on_policy_generated: Option<OnPolicyGeneratedCallback>,
}

impl<C: Clone> BucketUploadTokenProvider<C> {
    /// 基于存储空间和认证信息动态生成上传凭证实例
    #[inline]
    pub fn new(bucket: impl Into<BucketName>, upload_token_lifetime: Duration, credential: C) -> Self {
        Self::builder(bucket, upload_token_lifetime, credential).build()
    }

    /// 创建存储空间上传凭证构建器
    #[inline]
    pub fn builder(
        bucket: impl Into<BucketName>,
        upload_token_lifetime: Duration,
        credential: C,
    ) -> BucketUploadTokenProviderBuilder<C> {
        BucketUploadTokenProviderBuilder {
            inner: Self {
                bucket: bucket.into(),
                upload_token_lifetime,
                credential,
                on_policy_generated: None,
            },
        }
    }

    fn make_policy(&self) -> AnyResult<UploadPolicy> {
        let mut builder =
            UploadPolicyBuilder::new_policy_for_bucket(self.bucket.to_string(), self.upload_token_lifetime);
        if let Some(on_policy_generated) = self.on_policy_generated.as_ref() {
            on_policy_generated(&mut builder)?;
        }
        Ok(builder.build())
    }
}

impl<C: Clone> Debug for BucketUploadTokenProvider<C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("BucketUploadTokenProvider")
            .field("bucket", &self.bucket)
            .field("upload_token_lifetime", &self.upload_token_lifetime)
            .finish()
    }
}

impl<C: CredentialProvider + Clone> UploadTokenProvider for BucketUploadTokenProvider<C> {
    #[inline]
    fn access_key(&self, _opts: GetAccessKeyOptions) -> ParseResult<GotAccessKey> {
        Ok(self
            .credential
            .get(Default::default())?
            .into_credential()
            .split()
            .0
            .into())
    }

    fn policy(&self, _opts: GetPolicyOptions) -> ParseResult<GotUploadPolicy<'_>> {
        Ok(self.make_policy()?.into())
    }

    fn to_token_string(&self, _opts: ToStringOptions) -> ToStringResult<Cow<'_, str>> {
        Ok(Cow::Owned(
            self.credential
                .get(Default::default())?
                .sign_with_data(self.make_policy()?.as_json().as_bytes()),
        ))
    }
}

/// 存储空间上传凭证构建器
#[derive(Clone)]
pub struct BucketUploadTokenProviderBuilder<C: Clone> {
    inner: BucketUploadTokenProvider<C>,
}

impl<C: Clone> BucketUploadTokenProviderBuilder<C> {
    /// 设置上传凭证回调函数
    #[inline]
    #[must_use]
    pub fn on_policy_generated(
        mut self,
        callback: impl Fn(&mut UploadPolicyBuilder) -> AnyResult<()> + Sync + Send + 'static,
    ) -> Self {
        self.inner.on_policy_generated = Some(Arc::new(callback));
        self
    }

    /// 构造存储空间上传凭证
    #[inline]
    pub fn build(self) -> BucketUploadTokenProvider<C> {
        self.inner
    }
}

impl<C: Clone> Debug for BucketUploadTokenProviderBuilder<C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("BucketUploadTokenProviderBuilder")
            .field("bucket", &self.inner.bucket)
            .field("upload_token_lifetime", &self.inner.upload_token_lifetime)
            .finish()
    }
}

/// 基于对象的动态生成
///
/// 根据对象的快速生成上传凭证实例
#[derive(Clone)]
pub struct ObjectUploadTokenProvider<C: Clone> {
    bucket: BucketName,
    object: ObjectName,
    upload_token_lifetime: Duration,
    credential: C,
    on_policy_generated: Option<OnPolicyGeneratedCallback>,
}

impl<C: Clone> ObjectUploadTokenProvider<C> {
    /// 基于存储空间和对象名称和认证信息动态生成上传凭证实例
    #[inline]
    pub fn new(
        bucket: impl Into<BucketName>,
        object: impl Into<ObjectName>,
        upload_token_lifetime: Duration,
        credential: C,
    ) -> Self {
        Self::builder(bucket, object, upload_token_lifetime, credential).build()
    }

    /// 创建对象上传凭证构建器
    #[inline]
    pub fn builder(
        bucket: impl Into<BucketName>,
        object: impl Into<ObjectName>,
        upload_token_lifetime: Duration,
        credential: C,
    ) -> ObjectUploadTokenProviderBuilder<C> {
        ObjectUploadTokenProviderBuilder {
            inner: Self {
                bucket: bucket.into(),
                object: object.into(),
                upload_token_lifetime,
                credential,
                on_policy_generated: None,
            },
        }
    }

    fn make_policy(&self) -> AnyResult<UploadPolicy> {
        let mut builder = UploadPolicyBuilder::new_policy_for_object(
            self.bucket.to_string(),
            self.object.to_string(),
            self.upload_token_lifetime,
        );
        if let Some(on_policy_generated) = self.on_policy_generated.as_ref() {
            on_policy_generated(&mut builder)?;
        }
        Ok(builder.build())
    }
}

impl<C: Clone> Debug for ObjectUploadTokenProvider<C> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ObjectUploadTokenProvider")
            .field("bucket", &self.bucket)
            .field("object", &self.object)
            .field("upload_token_lifetime", &self.upload_token_lifetime)
            .finish()
    }
}

impl<C: CredentialProvider + Clone> UploadTokenProvider for ObjectUploadTokenProvider<C> {
    fn access_key(&self, _opts: GetAccessKeyOptions) -> ParseResult<GotAccessKey> {
        Ok(self
            .credential
            .get(Default::default())?
            .into_credential()
            .split()
            .0
            .into())
    }

    fn policy(&self, _opts: GetPolicyOptions) -> ParseResult<GotUploadPolicy<'_>> {
        Ok(self.make_policy()?.into())
    }

    fn to_token_string(&self, _opts: ToStringOptions) -> ToStringResult<Cow<'_, str>> {
        Ok(Cow::Owned(
            self.credential
                .get(Default::default())?
                .sign_with_data(self.make_policy()?.as_json().as_bytes()),
        ))
    }

解析 JSON 格式的上传凭证

Examples found in repository?
src/upload_token.rs (line 332)
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
    fn policy(&self, _opts: GetPolicyOptions) -> ParseResult<GotUploadPolicy<'_>> {
        self.policy
            .get_or_try_init(|| {
                let encoded_policy = self
                    .upload_token
                    .splitn(3, ':')
                    .last()
                    .ok_or(ParseError::InvalidUploadTokenFormat)?;
                let decoded_policy =
                    base64::decode(encoded_policy.as_bytes()).map_err(ParseError::Base64DecodeError)?;
                UploadPolicy::from_json(decoded_policy).map_err(ParseError::JsonDecodeError)
            })
            .map(Cow::Borrowed)
            .map(GotUploadPolicy::from)
    }

根据指定的上传策略字段获取相应的值

Examples found in repository?
src/upload_policy.rs (line 102)
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
    pub fn bucket(&self) -> Option<&str> {
        self.get(SCOPE_KEY)
            .as_ref()
            .and_then(|s| s.as_str())
            .and_then(|s| s.split(':').next())
    }

    /// 对象名称约束或对象名称前缀约束
    pub fn key(&self) -> Option<&str> {
        self.get(SCOPE_KEY)
            .as_ref()
            .and_then(|v| v.as_str())
            .and_then(|s| s.split_once(':').map(|x| x.1))
    }

    /// 是否是对象名称前缀约束
    pub fn use_prefixal_object_key(&self) -> bool {
        self.get(IS_PREFIXAL_SCOPE_KEY).and_then(|v| v.as_u64()).is_some()
    }

    /// 是否仅允许新增对象,不允许覆盖对象
    pub fn is_insert_only(&self) -> bool {
        self.get(INSERT_ONLY_KEY).and_then(|v| v.as_u64()).unwrap_or_default() > 0
    }

    /// 是否启用 MIME 类型自动检测
    pub fn mime_detection_enabled(&self) -> bool {
        self.get(DETECT_MIME_KEY).and_then(|v| v.as_u64()).unwrap_or_default() > 0
    }

    /// 上传凭证过期时间
    pub fn token_deadline(&self) -> Option<SystemTime> {
        self.get(DEADLINE_KEY)
            .and_then(|v| v.as_u64())
            .map(|t| SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(t)).unwrap())
    }

    /// Web 端文件上传成功后,浏览器执行 303 跳转的 URL
    pub fn return_url(&self) -> Option<&str> {
        self.get(RETURN_URL_KEY).and_then(|v| v.as_str())
    }

    /// 上传成功后,自定义七牛云最终返回给上传端的数据
    pub fn return_body(&self) -> Option<&str> {
        self.get(RETURN_BODY_KEY).and_then(|v| v.as_str())
    }

    /// 上传成功后,七牛云向业务服务器发送 POST 请求的 URL 列表
    pub fn callback_urls(&self) -> Option<Split<char>> {
        self.get(CALLBACK_URL_KEY)
            .and_then(|v| v.as_str())
            .map(|s| s.split(';'))
    }

    /// 上传成功后,七牛云向业务服务器发送回调请求时的 `Host`
    pub fn callback_host(&self) -> Option<&str> {
        self.get(CALLBACK_HOST_KEY).and_then(|v| v.as_str())
    }

    /// 上传成功后,七牛云向业务服务器发送回调请求时的内容
    ///
    /// 支持[魔法变量](https://developer.qiniu.com/kodo/manual/1235/vars#magicvar)和[自定义变量](https://developer.qiniu.com/kodo/manual/1235/vars#xvar)
    pub fn callback_body(&self) -> Option<&str> {
        self.get(CALLBACK_BODY_KEY).and_then(|v| v.as_str())
    }

    /// 上传成功后,七牛云向业务服务器发送回调请求时的 `Content-Type`
    ///
    /// 默认为 `application/x-www-form-urlencoded`,也可设置为 `application/json`
    pub fn callback_body_type(&self) -> Option<&str> {
        self.get(CALLBACK_BODY_TYPE_KEY).and_then(|v| v.as_str())
    }

    /// 自定义对象名称
    ///
    /// 支持[魔法变量](https://developer.qiniu.com/kodo/manual/1235/vars#magicvar)和[自定义变量](https://developer.qiniu.com/kodo/manual/1235/vars#xvar)
    pub fn save_key(&self) -> Option<&str> {
        self.get(SAVE_KEY_KEY).and_then(|v| v.as_str())
    }

    /// 是否忽略客户端指定的对象名称,强制使用自定义对象名称进行文件命名
    pub fn is_save_key_forced(&self) -> bool {
        self.get(FORCE_SAVE_KEY_KEY).and_then(|v| v.as_bool()).unwrap_or(false)
    }

    /// 限定上传文件尺寸的范围
    ///
    /// 返回的第一个元素为最小尺寸,第二个元素为最大尺寸,如果为 `None` 表示不限制,单位为字节
    pub fn file_size_limitation(&self) -> (Option<u64>, Option<u64>) {
        (
            self.get(FSIZE_MIN_KEY).and_then(|v| v.as_u64()),
            self.get(FSIZE_LIMIT_KEY).and_then(|v| v.as_u64()),
        )
    }

    /// 限定用户上传的文件类型
    ///
    /// 指定本字段值,七牛服务器会侦测文件内容以判断 MIME 类型,再用判断值跟指定值进行匹配,
    /// 匹配成功则允许上传,匹配失败则返回 403 状态码
    pub fn mime_types(&self) -> Option<Split<char>> {
        self.get(MIME_LIMIT_KEY).and_then(|v| v.as_str()).map(|s| s.split(';'))
    }

    /// 文件类型
    pub fn file_type(&self) -> Option<FileType> {
        self.get(FILE_TYPE_KEY).and_then(|v| v.as_u64()).map(FileType::from)
    }

    /// 对象生命周期
    ///
    /// 精确到天
    pub fn object_lifetime(&self) -> Option<Duration> {
        self.get(DELETE_AFTER_DAYS_KEY)
            .and_then(|v| v.as_u64())
            .map(|d| Duration::from_secs(d * 60 * 60 * 24))
    }

获取上传策略的字段迭代器

获取上传策略的字段值的迭代器

将上传策略转换为动态上传凭证提供者的实例

该方法与 UploadPolicy::into_static_upload_token_provider 的区别在于该方法接受 CredentialProvider 实例

Examples found in repository?
src/upload_policy.rs (line 265)
260
261
262
263
264
265
266
267
268
269
270
271
272
273
    pub fn into_static_upload_token_provider(
        self,
        credential: Credential,
        opts: ToStringOptions,
    ) -> StaticUploadTokenProvider {
        let provider = self.into_dynamic_upload_token_provider(credential);
        let token = provider.to_token_string(opts).unwrap();
        let token: StaticUploadTokenProvider = token.parse().unwrap();
        let (policy, credential) = provider.split();
        let (access_key, _) = credential.split();
        token.set_policy(policy);
        token.set_access_key(access_key);
        token
    }

将上传策略转换为静态上传凭证提供者的实例

该方法与 UploadPolicy::into_dynamic_upload_token_provider 的区别在于该方法只能接受 Credential 实例

Examples found in repository?
src/upload_policy.rs (line 565)
564
565
566
    pub fn build_token(&self, credential: Credential, opts: ToStringOptions) -> StaticUploadTokenProvider {
        self.build().into_static_upload_token_provider(credential, opts)
    }

Trait Implementations§

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
This method tests for self and other values to be equal, and is used by ==.
This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

Blanket Implementations§

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Should always be Self
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.