之前介紹了civetweb作爲radosgw的agent的運行機制,請看下面鏈接
http://blog.csdn.net/zrs19800702/article/details/53081444
那麼S3的消息如何解析的呢?
下面介紹下消息解析
在civetweb的子線程運行的函數中可以看出存在一個 struct mg_connection *conn指針,這個就是保持解析後消息的
static void *worker_thread_run(void *thread_func_param)
{
struct mg_context *ctx = (struct mg_context *) thread_func_param;
struct mg_connection *conn;
struct mg_workerTLS tls;
tls.is_master = 0;
#if defined(_WIN32) && !defined(__SYMBIAN32__)
tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
#endif
conn = (struct mg_connection *) mg_calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
if (conn == NULL) {
mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
} else {
pthread_setspecific(sTlsKey, &tls);
conn->buf_size = MAX_REQUEST_SIZE;------設置buff大小
conn->buf = (char *) (conn + 1);
conn->ctx = ctx;
conn->request_info.user_data = ctx->user_data;----------此處將消息指針賦值過去
/* Allocate a mutex for this connection to allow communication both
within the request handler and from elsewhere in the application */
(void) pthread_mutex_init(&conn->mutex, NULL);
/* Call consume_socket() even when ctx->stop_flag > 0, to let it
signal sq_empty condvar to wake up the master waiting in
produce_socket() */
while (consume_socket(ctx, &conn->client)) {
conn->birth_time = time(NULL);
/* Fill in IP, port info early so even if SSL setup below fails,
error handler would have the corresponding info.
Thanks to Johannes Winkelmann for the patch.
TODO(lsm): Fix IPv6 case */
conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);
memcpy(&conn->request_info.remote_ip,
&conn->client.rsa.sin.sin_addr.s_addr, 4);
conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);
conn->request_info.is_ssl = conn->client.is_ssl;
if (!conn->client.is_ssl
#ifndef NO_SSL
|| sslize(conn, conn->ctx->ssl_ctx, SSL_accept)
#endif
) {
process_new_connection(conn);-------------------------處理消息
}
close_connection(conn);
}
}
/* Signal master that we're done with connection and exiting */
(void) pthread_mutex_lock(&ctx->thread_mutex);
ctx->num_threads--;
(void) pthread_cond_signal(&ctx->thread_cond);
assert(ctx->num_threads >= 0);
(void) pthread_mutex_unlock(&ctx->thread_mutex);
pthread_setspecific(sTlsKey, NULL);
#if defined(_WIN32) && !defined(__SYMBIAN32__)
CloseHandle(tls.pthread_cond_helper_mutex);
#endif
mg_free(conn);
DEBUG_TRACE("exiting");
return NULL;
}
在static void process_new_connection(struct mg_connection *conn)中將消息轉換成一個mg_request_info類型的結構,
struct mg_request_info *ri = &conn->request_info;
------
下面開始讀取消息內容
conn->data_len = 0;
do {
int err;
if (!getreq(conn, ebuf, sizeof(ebuf), &err)) {
if (err > 0) {
send_http_error(conn, err, "Bad Request", "%s", ebuf);
}
conn->must_close = 1;
} else if (!is_valid_uri(conn->request_info.uri)) {
snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);
send_http_error(conn, 400, "Bad Request", "%s", ebuf);
} else if (strcmp(ri->http_version, "1.0") &&
strcmp(ri->http_version, "1.1")) {
snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);
send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);
}
if (ebuf[0] == '\0') {
handle_request(conn);-----開始處理消息,這裏會進入函數
----------------------------------------------------------------------------------
} else if (conn->ctx->callbacks.begin_request != NULL &&
conn->ctx->callbacks.begin_request(conn)) {-------------------------------------此處進入回調函數civetweb_callback()------------->process_request()進行消息處理
process_request()之前會聲明一個類RGWMongoose繼承了 RGWStreamIO,這個類裏面有兩個bufflist
bufferlist header_data;---數據頭內容
bufferlist data;----數據內容
採用以下兩個方法讀取數據和寫數據
int write_data(const char *buf, int len);
int read_data(char *buf, int len);
以下拿put object方法舉例子:
process_request()中的
client_io->init(g_ceph_context);----初始化env_map,獲取相關參數
void RGWMongoose::init_env(CephContext *cct)中獲取request_info的http_headers信息存入緩存
RGWHandler_REST *handler = rest->get_handler(store, s, client_io, &mgr, &init_error);----new RGWHandler_REST_Obj_S3;
......
op = handler->get_op(store);----------new RGWPutObj_ObjStore_S3; 這時候RGWMongoose的指針已經存入到struct req_state *s中了,
這裏的op類型是RGWPutObj_ObjStore_S3,然後調用op->init(store, s, this);保存了三個變量到RGWPutObj_ObjStore_S3的父類RGWOp中
this->store = store;
this->s = s;
this->dialect_handler = dialect_handler;
......
op->execute();---------執行具體業務,這裏面會調用get_data方法如下:
do {
bufferlist data;
len = get_data(data);-----------循環讀取數據,按照配置文件的塊大小讀取
......
ofs += len;
} while (len > 0);
......
先調用RGWPutObj_ObjStore_S3中 get_data(bufferlist& bl);---->int ret = RGWPutObj_ObjStore::get_data(bl)中詳細如下
int RGWPutObj_ObjStore::get_data(bufferlist& bl)
{
size_t cl;
uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size;--------------獲取配置文件的塊大小,RGWOp中保存了struct req_state *s(裏面有RGWClientIO *cio,調用到RGWMongoose的read方法讀取數據)
if (s->length) {
cl = atoll(s->length) - ofs;
if (cl > chunk_size)
cl = chunk_size;
} else {
cl = chunk_size;
}
int len = 0;
if (cl) {
bufferptr bp(cl);------初始化每個bufferptr的塊大小
int read_len; /* cio->read() expects int * */
int r = STREAM_IO(s)->read(bp.c_str(), cl, &read_len, s->aws4_auth_needs_complete);--------讀取數據到bp,這裏調用的是RGWMongoose的read
if (r < 0) {
return r;
}
len = read_len;
bl.append(bp, 0, len);---------添加到bl中
}
if ((uint64_t)ofs + len > s->cct->_conf->rgw_max_put_size) {
return -ERR_TOO_LARGE;
}
if (!ofs)
supplied_md5_b64 = s->info.env->get("HTTP_CONTENT_MD5");
return len;
}
.....
---------------------------------------------------------------------------------
if (conn->ctx->callbacks.end_request != NULL) {
conn->ctx->callbacks.end_request(conn, conn->status_code);------------------處理完消息後的回調函數,這裏的回調函數end_request在運行前爲NULL
}
log_access(conn);---------------------------處理日誌
}
下面是gdb調試打印出來的conn內容,關注紅色字段
S3的命令是gettorrent,後面有一個put object的內容
Breakpoint 2, process_new_connection (conn=0x7fdebc0009b0) at civetweb/src/civetweb.c:6577
6577 if (ebuf[0] == '\0') {
$3 = {
request_info = {
request_method = 0x7fdebc000ed0 "GET",
uri = 0x7fdebc000ed4 "/ZHOU/ceph-0.87.2.tar.gz?get_torrent",
http_version = 0x7fdebc000efe "1.1",
query_string = 0x7fdebc000eed "get_torrent",
remote_user = 0x0,
remote_ip = 2130706433,
remote_port = 48716,
is_ssl = 0,
user_data = 0x7fdeeaff6328,
conn_data = 0x0,
num_headers = 4,
http_headers = {{
name = 0x7fdebc000f03 "Host",
value = 0x7fdebc000f09 "localhost:8000"
}, {
name = 0x7fdebc000f19 "Accept-Encoding",
value = 0x7fdebc000f2a "identity"
}, {
name = 0x7fdebc000f34 "Authorization",
value = 0x7fdebc000f43 "AWS 0555b35654ad1656d804:RIAZqLoZnSVotvWOCGi2dcXlAsU="
}, {
name = 0x7fdebc000f7a "x-amz-date",
value = 0x7fdebc000f86 "Thu, 19 May 2016 06:54:39 +0000"
}, {
name = 0x7fdebc000fa8 "",
value = 0x7fdebc000fa8 ""
}, {
name = 0x7fdebc000fa9 "",
value = 0x7fdebc000fa9 ""
}, {
name = 0x0,
value = 0x0
} <repeats 58 times>}
},
ctx = 0x7fdeeaff6800,
ssl = 0x0,
client_ssl_ctx = 0x0,
client = {
sock = 7,
lsa = {
sa = {
sa_family = 2,
sa_data = "\037@\177\000\000\001\000\000\000\000\000\000\000"
},
sin = {
sin_family = 2,
sin_port = 16415,
sin_addr = {
s_addr = 16777343
},
sin_zero = "\000\000\000\000\000\000\000"
}
},
rsa = {
sa = {
sa_family = 2,
sa_data = "\276L\177\000\000\001\000\000\000\000\000\000\000"
},
sin = {
sin_family = 2,
sin_port = 19646,
sin_addr = {
s_addr = 16777343
},
sin_zero = "\000\000\000\000\000\000\000"
}
},
is_ssl = 0,
ssl_redir = 0
},
birth_time = 1463640879,
num_bytes_sent = 0,
content_len = 0,
consumed_content = 0,
buf = 0x7fdebc000ed0 "GET",
path_info = 0x0,
must_close = 0,
---Type <return> to continue, or q <return> to quit---
in_error_handler = 0,
buf_size = 16384,
request_len = 217,
data_len = 217,
status_code = -1,
throttle = 0,
last_throttle_time = 0,
last_throttle_bytes = 0,
mutex = {
__data = {
__lock = 0,
__count = 0,
__owner = 0,
__nusers = 0,
__kind = 0,
__spins = 0,
__list = {
__prev = 0x0,
__next = 0x0
}
},
__size = '\000' <repeats 39 times>,
__align = 0
},
is_chunked = 0
}
put objject消息,此處設置mutipart=false
Breakpoint 2, process_new_connection (conn=0x7fdecc000e40) at civetweb/src/civetweb.c:6577
6577 if (ebuf[0] == '\0') {
$23 = {
request_info = {
request_method = 0x7fdecc001360 "PUT",
uri = 0x7fdecc001364 "/ZHOU/pydev.tar.gz",
http_version = 0x7fdecc00137c "1.1",
query_string = 0x0,
remote_user = 0x0,
remote_ip = 2130706433,
remote_port = 48730,
is_ssl = 0,
user_data = 0x7fdeeaff6328,
conn_data = 0x0,
num_headers = 8,
http_headers = {{
name = 0x7fdecc001381 "Host",
value = 0x7fdecc001387 "localhost:8000"
}, {
name = 0x7fdecc001397 "Accept-Encoding",
value = 0x7fdecc0013a8 "identity"
}, {
name = 0x7fdecc0013b2 "Authorization",
value = 0x7fdecc0013c1 "AWS 0555b35654ad1656d804:B7/sdrvLeTnuaom5+TM7meN/BCU="
}, {
name = 0x7fdecc0013f8 "content-length",
value = 0x7fdecc001408 "46857122"
}, {
name = 0x7fdecc001412 "content-type",
value = 0x7fdecc001420 "application/x-gzip"
}, {
name = 0x7fdecc001434 "x-amz-date",
value = 0x7fdecc001440 "Thu, 19 May 2016 07:08:42 +0000"
}, {
name = 0x7fdecc001461 "x-amz-meta-s3cmd-attrs",
value = 0x7fdecc001479 "uid:0/gname:root/uname:root/gid:0/mode:33188/mtime:1463637551/atime:1463637588/md5:54d762d04b2f22368855a20f91154c53/ctime:1463637551"
}, {
name = 0x7fdecc0014ff "x-amz-storage-class",
value = 0x7fdecc001514 "STANDARD"
}, {
name = 0x7fdecc00151f "",
value = 0x7fdecc00151f ""
}, {
name = 0x0,
value = 0x0
} <repeats 55 times>}
},
ctx = 0x7fdeeaff6800,
ssl = 0x0,
client_ssl_ctx = 0x0,
client = {
sock = 7,
lsa = {
sa = {
sa_family = 2,
sa_data = "\037@\177\000\000\001\000\000\000\000\000\000\000"
},
sin = {
sin_family = 2,
sin_port = 16415,
sin_addr = {
s_addr = 16777343
},
sin_zero = "\000\000\000\000\000\000\000"
}
},
rsa = {
sa = {
sa_family = 2,
sa_data = "\276Z\177\000\000\001\000\000\000\000\000\000\000"
},
sin = {
sin_family = 2,
sin_port = 23230,
sin_addr = {
s_addr = 16777343
},
sin_zero = "\000\000\000\000\000\000\000"
}
},
is_ssl = 0,
ssl_redir = 0
},
birth_time = 1463641722,
num_bytes_sent = 0,
content_len = 46857122,
consumed_content = 0,
buf = 0x7fdecc001360 "PUT",
path_info = 0x0,
must_close = 0,
in_error_handler = 0,
buf_size = 16384,
request_len = 448,
data_len = 16384,
status_code = -1,
throttle = 0,
last_throttle_time = 0,
last_throttle_bytes = 0,
mutex = {
__data = {
__lock = 0,
__count = 0,
__owner = 0,
__nusers = 0,
__kind = 0,
__spins = 0,
__list = {
__prev = 0x0,
__next = 0x0
}
},
__size = '\000' <repeats 39 times>,
__align = 0
},
is_chunked = 0
}