文档章节

S3奇淫技巧:一步完成上传及ACL设置

秦牧羊
 秦牧羊
发布于 2017/06/28 14:33
字数 1018
阅读 102
收藏 0
点赞 1
评论 0

需求描述

用户A需要在上传文件到S3的同时设置允许用户test1可读,上传数据和设置ACL需要一步完成。其目的是尽量减少http请求次数,提高并发效率。

python用例

from boto.s3.connection import S3Connection
import boto
import os

endpoint = 's3.ceph.work'
bucket_name = 'test3'
access_key = ''
secret_key = ''
key_name = 'abc'

conn = boto.connect_s3(
    aws_access_key_id=access_key,
    aws_secret_access_key=secret_key,
    host=endpoint,
    is_secure=False,
    calling_format=boto.s3.connection.SubdomainCallingFormat(),
    validate_certs=False,
)

bucket = conn.get_bucket(bucket_name)
key_ = bucket.new_key(key_name)

#方法1,通常一般用这个方法
key_.set_contents_from_string('aa') #第一次http请求,PUT操作,上传数据
key_.add_user_grant('READ','test1') #第二次http请求,PUT操作,设置ACL

#方法2,设置http请求头
headers = {"x-amz-grant-read":"id=test1"} #这里切记要在id(type)后面加上"=",不然就踩坑了
key_.set_contents_from_string('aa', headers=headers) #一次http请求,PUT操作,上传数据同时设置Object的ACL

原理说明

方法2其实也是遵循了S3标准的操作,只需要在上传Object的HTTP请求header中加入"x-amz-acl"或“x-amz-grant-permission”,目前ceph已经实现了emailAddress、id、url三种类型认证方式,但是注意提交的value,一定要用 type=value的形式,下面介绍一下rgw中的源码具体实现。

S3中关于上传Object的具体标准请参考如下 http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUTacl.html

RGW的实现

第一步根据之前源码介绍的找入口方法,定位到以下函数

#src/rgw/rgw_rest_s3.cc
RGWOp *RGWHandler_REST_Obj_S3::op_put()
{
  if (is_acl_op()) {
    return new RGWPutACLs_ObjStore_S3;
  }
  if (s->init_state.src_bucket.empty())
    return new RGWPutObj_ObjStore_S3; #这里对应的是PUT方式上传Object
  else
    return new RGWCopyObj_ObjStore_S3;
}

再看一下这个类的定义如下

#src/rgw/rgw_rest_s3.cc
class RGWPutObj_ObjStore_S3 : public RGWPutObj_ObjStore {
public:
  RGWPutObj_ObjStore_S3() {}
  ~RGWPutObj_ObjStore_S3() {}

  int get_params(); #这里实现HTTP请求头的数据处理
  int get_data(bufferlist& bl);
  void send_response();

  int validate_aws4_single_chunk(char *chunk_str,
                                 char *chunk_data_str,
                                 unsigned int chunk_data_size,
                                 string chunk_signature);
  int validate_and_unwrap_available_aws4_chunked_data(bufferlist& bl_in,
                                                      bufferlist& bl_out);
};

在get_params的实现中通过create_s3_policy来实现对policy的构建

#src/rgw/rgw_rest_s3.cc

int RGWPutObj_ObjStore_S3::get_params()
{
  RGWObjectCtx& obj_ctx = *static_cast<RGWObjectCtx *>(s->obj_ctx);
  map<string, bufferlist> src_attrs;
  size_t pos;
  int ret;

  RGWAccessControlPolicy_S3 s3policy(s->cct);
  if (!s->length)
    return -ERR_LENGTH_REQUIRED;

  ret = create_s3_policy(s, store, s3policy, s->owner); #创建policy
  if (ret < 0)
    return ret;

  policy = s3policy;
  
  

再看一下create_s3_policy有两类s3policy的构建方法,一类是create_from_headers,另外一类是create_canned,我们这里是通过http header设置,所以选create_from_headers

#src/rgw/rgw_rest_s3.cc
static int create_s3_policy(struct req_state *s, RGWRados *store,
			    RGWAccessControlPolicy_S3& s3policy,
			    ACLOwner& owner)
{
  if (s->has_acl_header) {
    if (!s->canned_acl.empty())
      return -ERR_INVALID_REQUEST;

    return s3policy.create_from_headers(store, s->info.env, owner);
  }

  return s3policy.create_canned(owner, s->bucket_owner, s->canned_acl);
}

再看一下create_from_headers的实现,其基本流程是遍历s3_acl_header获得对应HTTP的ACL类型,最后通过parse_grantee_str生成对应的规则

#src/rgw/rgw_acl_s3.cc
static const s3_acl_header acl_header_perms[] = {
  {RGW_PERM_READ, "HTTP_X_AMZ_GRANT_READ"},
  {RGW_PERM_WRITE, "HTTP_X_AMZ_GRANT_WRITE"},
  {RGW_PERM_READ_ACP,"HTTP_X_AMZ_GRANT_READ_ACP"},
  {RGW_PERM_WRITE_ACP, "HTTP_X_AMZ_GRANT_WRITE_ACP"},
  {RGW_PERM_FULL_CONTROL, "HTTP_X_AMZ_GRANT_FULL_CONTROL"},
  {0, NULL}
};

int RGWAccessControlPolicy_S3::create_from_headers(RGWRados *store, RGWEnv *env, ACLOwner& _owner)
{
  std::list<ACLGrant> grants;
 
  for (const struct s3_acl_header *p = acl_header_perms; p->rgw_perm; p++) {
    if (parse_acl_header(store, env, p, grants) < 0) #根据匹配到的header生成对应acl
      return false;
  }

  RGWAccessControlList_S3& _acl = static_cast<RGWAccessControlList_S3 &>(acl);
  int r = _acl.create_from_grants(grants);

  owner = _owner;

  return r;
}


static int parse_acl_header(RGWRados *store, RGWEnv *env,
         const struct s3_acl_header *perm, std::list<ACLGrant>& _grants)
{
  std::list<string> grantees;
  std::string hacl_str;

  const char *hacl = get_acl_header(env, perm);
  if (hacl == NULL)
    return 0;

  hacl_str = hacl;
  get_str_list(hacl_str, ",", grantees);

  for (list<string>::iterator it = grantees.begin(); it != grantees.end(); ++it) {
    ACLGrant grant;
    int ret = parse_grantee_str(store, *it, perm, grant); #最终实现acl的匹配在这里面
    if (ret < 0)
      return ret;

    _grants.push_back(grant);
  }

  return 0;
}

static int parse_grantee_str(RGWRados *store, string& grantee_str,
        const struct s3_acl_header *perm, ACLGrant& grant)
{
  string id_type, id_val_quoted;
  int rgw_perm = perm->rgw_perm;
  int ret;

  RGWUserInfo info;

  ret = parse_key_value(grantee_str, id_type, id_val_quoted); #注意这里对header中传进来的type=value进行处理
  if (ret < 0)
    return ret;

  string id_val = rgw_trim_quotes(id_val_quoted);

  if (strcasecmp(id_type.c_str(), "emailAddress") == 0) {
    ret = rgw_get_user_info_by_email(store, id_val, info);
    if (ret < 0)
      return ret;

    grant.set_canon(info.user_id, info.display_name, rgw_perm);
  } else if (strcasecmp(id_type.c_str(), "id") == 0) {
    rgw_user user(id_val);
    ret = rgw_get_user_info_by_uid(store, user, info);
    if (ret < 0)
      return ret;

    grant.set_canon(info.user_id, info.display_name, rgw_perm);
  } else if (strcasecmp(id_type.c_str(), "uri") == 0) {
    ACLGroupTypeEnum gid = grant.uri_to_group(id_val);
    if (gid == ACL_GROUP_NONE)
      return -EINVAL;

    grant.set_group(gid, rgw_perm);
  } else {
    return -EINVAL;
  }

  return 0;
}

这里需要重点提到的一点就是在parse_grantee_str中parse_key_value方法,如果你传进来的header字段的value不包含"=",那么你就悲剧了。

#src/rgw/rgw_common.cc
int parse_key_value(string& in_str, const char *delim, string& key, string& val)
{
  if (delim == NULL)
    return -EINVAL;

  int pos = in_str.find(delim);
  if (pos < 0)
    return -EINVAL;

  trim_whitespace(in_str.substr(0, pos), key);
  pos++;

  trim_whitespace(in_str.substr(pos), val);

  return 0;
}

int parse_key_value(string& in_str, string& key, string& val)
{
  return parse_key_value(in_str, "=", key,val); #将header里的value按"="进行拆分
}

© 著作权归作者所有

共有 人打赏支持
秦牧羊
粉丝 69
博文 57
码字总数 28980
作品 0
广州
架构师
rgw object read and write

一、Get Object。 1、读取Object的主要处理流程。 RGWGetObj::execute() |创建RGWGetObjCB类实例,其中handledata()函数为回调函数,该函数会调用RGWGetObj::getdatacb()函数,而该函数最终会...

linuxhunter
2016/04/12
364
4
全世界最短IE判定if(!+[1,])的解释

<script type="text/javascript">alert([1,2]);//相当于alert([1,2].toString()); --这在IE与非IE上都相同,都会弹出"1,2"alert([1,]);//相当于alert([1,].toString());--在非IE的标准浏览器......

大师兄
2015/06/11
0
0
ossutil的过滤参数include/exclude

应用场景 某些用户在本地或者OSS上存放了不同类型的文件,比如jpg文件和pptx文件。用户希望在(批量)上传jpg文件的时候设置不同的meta和ACL,而(批量)上传pptx文件的时候设置另外的meta和...

zuozhao
06/06
0
0
RGW S3 ACL解析

RGW ACL主要类关系图如下图所示: RGW ACL处理类关系图如下图所示: RGW ACL主要处理流程详细说明如下。 一、PUT ACL。 RGWPutACL::execute() |从HTTP请求数据流中解析出RGWAccessControlPol...

linuxhunter
2016/04/14
89
0
RGW S3 Multipart解析

S3分段上传技术主要应用在大文件的数据上传上,通常在S3客户端会对上传的大文件做一次分片操作。在RGW内部还会对S3客户端发送过来的数据再进行一次分片处理,RGW默认分片大小是4MB。下面就M...

linuxhunter
2016/04/13
255
1
Maven奇淫技巧

Maven奇淫技巧 命令行窗口指定settings.xml 命令如下:

xjt2016
2016/11/21
12
0
Android系统更改状态栏字体颜色

Android系统更改状态栏字体颜色 码农明明桑2016-01-08579 阅读 android 随着时代的发展,Android的状态栏都不是乌黑一片了,在Android4.4之后我们可以修改状态栏的颜色或者让我们自己的View延...

码农明明桑
2016/01/08
0
0
comet 异步请求技术中相关关键字解释 (新手向)

最近想在产品中加入即时通讯的功能.BS架构的程序.实现方式不外乎两大标准下的各种奇淫技巧. 这两大标准就是 HTML5 HTML4 为啥这两个呢..因为HTML5里面有websocket.这个彻底颠覆http请求的东西...

架构梦想
2013/04/26
0
11
Linux服务器通过aws命令行上传文件至S3

目的 Linux服务器通过AWS命令行上传文件至S3 配置 打开你的AWS控制台; 连接你的Linux服务器,按照以下步骤操作; # 安装pip yum -y install python-pip # 安装awscli pip install awscli #...

M玺
2017/05/17
0
0
IDEA奇淫技巧

tomcat部署时war和war exploded区别 war模式—-将WEB工程以包的形式上传到服务器 war exploded模式—-将WEB工程以当前文件夹的位置关系上传到服务器 一图解释 一些使用习惯 Eclipse可以在Pro...

xjt2016
2016/12/06
45
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

c++ qt 组播总结

每个人都有不同的认知规律和习惯, 有的人喜欢搞一套严密的大理论, 论述起来滔滔不绝, 不管自己懂不懂, 反正读者/听者是没搞懂。 有的人喜欢从实践出发, 没看到代码, 不运行一下, 不看...

backtrackx
4分钟前
0
0
Sublime text2安装json格式化插件SublimePrettyJson[Windows]

一、下载SublimePrettyJson插件包 https://github.com/dzhibas/SublimePrettyJson 二、将下载的文件解压放到在package目录下面 C:\Users\lucky\AppData\Roaming\Sublime Text 3\Packages 每个......

lazy~
4分钟前
0
0
安装vue-cli 报4058错误

1. 4058是网络代理错误。 安装淘宝源修改一下就可以了: npm --registry https://registry.npm.taobao.org info underscore 改为cnpm执行: cnpm install --global vue-cli 安装成功: 试试版...

MrBoyce
5分钟前
0
0
CPU飙升分析

1、top -----看具体的进程 2、top -H -p pid ------该进程的线程 3、printf 0x%x 15248 ------将线程改为16进制 4、jstack 进程...

北极之北
8分钟前
1
0
新生代Eden与两个Survivor区的解释

聊聊JVM的年轻代 1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能。你先想想,如果没有分代,那我...

浮躁的码农
10分钟前
0
0
【JVM】JSTATD结合Java VisualVM进行远程监控JVM运行情况(二)

内存泄露指的是程序中动态分配内存给一些临时对象,但是对象不会被GC(java垃圾回收机制gabage collection)所回收,它始终占用内存。即被分配的对象很大但已无用; 内存溢出指的是程序运行过...

大白来袭
13分钟前
1
0
聊聊ribbon的超时时间设置

序 本文主要研究一下ribbon的超时时间设置 配置 实例 ribbon: ReadTimeout: 10000 ConnectTimeout: 10000 MaxAutoRetries: 0 MaxAutoRetriesNextServer: 1 eureka: enabled: ......

go4it
21分钟前
0
0
一行代码结果叹为观止,能做到这么极致的也只有python了

Python 这门语言非常的有趣,不仅可以做高大上的人工智能、大数据、机器学习。还可以用来做 Web、爬虫。还有其它很多的应用。今天我就给大家展示下一行 Python 代码都可以做些什么。 一行打印...

猫咪编程
25分钟前
2
0
KingShard使用

对于kingshard的功能,在git中可以看到明确的功能说明 主要功能: 1. 基础功能 支持SQL读写分离。 支持透明的MySQL连接池,不必每次新建连接。 支持平滑上线DB或下线DB,前端应用无感知。 支...

mickelfeng
27分钟前
0
0
Linux 下 查找某个字符串

如果你想在当前项目下 查找 "test" 这个字符串,可以这样: grep -rn "test" * * : 表示当前目录所有文件,也可以是某个文件名-r 是递归查找-n 是显示行号-R ...

nsns
27分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部