Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
4e9fb447
T
TDengine
项目概览
taosdata
/
TDengine
大约 1 年 前同步成功
通知
1184
Star
22015
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
4e9fb447
编写于
8月 09, 2021
作者:
S
Shengliang Guan
提交者:
GitHub
8月 09, 2021
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #7218 from taosdata/feature/TD-5784-2.0
[TD-5784]<fix>: fixed some potential memory leak bugs
上级
a93326c9
1cf81a85
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
231 addition
and
114 deletion
+231
-114
src/plugins/http/inc/httpParser.h
src/plugins/http/inc/httpParser.h
+66
-1
src/plugins/http/src/httpParser.c
src/plugins/http/src/httpParser.c
+148
-109
src/plugins/http/src/httpUtil.c
src/plugins/http/src/httpUtil.c
+17
-4
未找到文件。
src/plugins/http/inc/httpParser.h
浏览文件 @
4e9fb447
...
...
@@ -17,7 +17,71 @@
#define HTTP_PARSER_H
#include "httpGzip.h"
#define HTTP_MAX_URL 5 // http url stack size
#define HTTP_MAX_URL 6 // http url stack size
#define HTTP_CODE_CONTINUE 100
#define HTTP_CODE_SWITCHING_PROTOCOL 101
#define HTTP_CODE_PROCESSING 102
#define HTTP_CODE_EARLY_HINTS 103
#define HTTP_CODE_OK 200
#define HTTP_CODE_CREATED 201
#define HTTP_CODE_ACCEPTED 202
#define HTTP_CODE_NON_AUTHORITATIVE_INFO 203
#define HTTP_CODE_NO_CONTENT 204
#define HTTP_CODE_RESET_CONTENT 205
#define HTTP_CODE_PARTIAL_CONTENT 206
#define HTTP_CODE_MULTI_STATUS 207
#define HTTP_CODE_ALREADY_REPORTED 208
#define HTTP_CODE_IM_USED 226
#define HTTP_CODE_MULTIPLE_CHOICE 300
#define HTTP_CODE_MOVED_PERMANENTLY 301
#define HTTP_CODE_FOUND 302
#define HTTP_CODE_SEE_OTHER 303
#define HTTP_CODE_NOT_MODIFIED 304
#define HTTP_CODE_USE_PROXY 305
#define HTTP_CODE_UNUSED 306
#define HTTP_CODE_TEMPORARY_REDIRECT 307
#define HTTP_CODE_PERMANENT_REDIRECT 308
#define HTTP_CODE_BAD_REQUEST 400
#define HTTP_CODE_UNAUTHORIZED 401
#define HTTP_CODE_PAYMENT_REQUIRED 402
#define HTTP_CODE_FORBIDDEN 403
#define HTTP_CODE_NOT_FOUND 404
#define HTTP_CODE_METHOD_NOT_ALLOWED 405
#define HTTP_CODE_NOT_ACCEPTABLE 406
#define HTTP_CODE_PROXY_AUTH_REQUIRED 407
#define HTTP_CODE_REQUEST_TIMEOUT 408
#define HTTP_CODE_CONFLICT 409
#define HTTP_CODE_GONE 410
#define HTTP_CODE_LENGTH_REQUIRED 411
#define HTTP_CODE_PRECONDITION_FAILED 412
#define HTTP_CODE_PAYLOAD_TOO_LARGE 413
#define HTTP_CODE_URI_TOO_LARGE 414
#define HTTP_CODE_UNSUPPORTED_MEDIA_TYPE 415
#define HTTP_CODE_RANGE_NOT_SATISFIABLE 416
#define HTTP_CODE_EXPECTATION_FAILED 417
#define HTTP_CODE_IM_A_TEAPOT 418
#define HTTP_CODE_MISDIRECTED_REQUEST 421
#define HTTP_CODE_UNPROCESSABLE_ENTITY 422
#define HTTP_CODE_LOCKED 423
#define HTTP_CODE_FAILED_DEPENDENCY 424
#define HTTP_CODE_TOO_EARLY 425
#define HTTP_CODE_UPGRADE_REQUIRED 426
#define HTTP_CODE_PRECONDITION_REQUIRED 428
#define HTTP_CODE_TOO_MANY_REQUESTS 429
#define HTTP_CODE_REQ_HDR_FIELDS_TOO_LARGE 431
#define HTTP_CODE_UNAVAIL_4_LEGAL_REASONS 451
#define HTTP_CODE_INTERNAL_SERVER_ERROR 500
#define HTTP_CODE_NOT_IMPLEMENTED 501
#define HTTP_CODE_BAD_GATEWAY 502
#define HTTP_CODE_SERVICE_UNAVAILABLE 503
#define HTTP_CODE_GATEWAY_TIMEOUT 504
#define HTTP_CODE_HTTP_VER_NOT_SUPPORTED 505
#define HTTP_CODE_VARIANT_ALSO_NEGOTIATES 506
#define HTTP_CODE_INSUFFICIENT_STORAGE 507
#define HTTP_CODE_LOOP_DETECTED 508
#define HTTP_CODE_NOT_EXTENDED 510
#define HTTP_CODE_NETWORK_AUTH_REQUIRED 511
typedef
enum
HTTP_PARSER_STATE
{
HTTP_PARSER_BEGIN
,
...
...
@@ -36,6 +100,7 @@ typedef enum HTTP_PARSER_STATE {
HTTP_PARSER_CHUNK
,
HTTP_PARSER_END
,
HTTP_PARSER_ERROR
,
HTTP_PARSER_OPTIONAL_SP
}
HTTP_PARSER_STATE
;
typedef
enum
HTTP_AUTH_TYPE
{
...
...
src/plugins/http/src/httpParser.c
浏览文件 @
4e9fb447
...
...
@@ -25,70 +25,70 @@
static
void
httpOnData
(
ehttp_gzip_t
*
gzip
,
void
*
arg
,
const
char
*
buf
,
int32_t
len
);
static
HttpStatus
httpStatusCodes
[]
=
{
{
100
,
"Continue"
},
{
101
,
"Switching Protocol"
},
{
102
,
"Processing (WebDAV)"
},
{
103
,
"Early Hints"
},
{
200
,
"OK"
},
{
201
,
"Created"
},
{
202
,
"Accepted"
},
{
203
,
"Non-Authoritative Information"
},
{
204
,
"No Content"
},
{
205
,
"Reset Content"
},
{
206
,
"Partial Content"
},
{
207
,
"Multi-Status (WebDAV)"
},
{
208
,
"Already Reported (WebDAV)"
},
{
226
,
"IM Used (HTTP Delta encoding)"
},
{
300
,
"Multiple Choice"
},
{
301
,
"Moved Permanently"
},
{
302
,
"Found"
},
{
303
,
"See Other"
},
{
304
,
"Not Modified"
},
{
305
,
"Use Proxy"
},
{
306
,
"unused"
},
{
307
,
"Temporary Redirect"
},
{
308
,
"Permanent Redirect"
},
{
400
,
"Bad Request"
},
{
401
,
"Unauthorized"
},
{
402
,
"Payment Required"
},
{
403
,
"Forbidden"
},
{
404
,
"Not Found"
},
{
405
,
"Method Not Allowed"
},
{
406
,
"Not Acceptable"
},
{
407
,
"Proxy Authentication Required"
},
{
408
,
"Request Timeout"
},
{
409
,
"Conflict"
},
{
410
,
"Gone"
},
{
411
,
"Length Required"
},
{
412
,
"Precondition Failed"
},
{
413
,
"Payload Too Large"
},
{
414
,
"URI Too Long"
},
{
415
,
"Unsupported Media Type"
},
{
416
,
"Range Not Satisfiable"
},
{
417
,
"Expectation Failed"
},
{
418
,
"I'm a teapot"
},
{
421
,
"Misdirected Request"
},
{
422
,
"Unprocessable Entity (WebDAV)"
},
{
423
,
"Locked (WebDAV)"
},
{
424
,
"Failed Dependency (WebDAV)"
},
{
425
,
"Too Early"
},
{
426
,
"Upgrade Required"
},
{
428
,
"Precondition Required"
},
{
429
,
"Too Many Requests"
},
{
431
,
"Request Header Fields Too Large"
},
{
451
,
"Unavailable For Legal Reasons"
},
{
500
,
"Internal Server Error"
},
{
501
,
"Not Implemented"
},
{
502
,
"Bad Gateway"
},
{
503
,
"Service Unavailable"
},
{
504
,
"Gateway Timeout"
},
{
505
,
"HTTP Version Not Supported"
},
{
506
,
"Variant Also Negotiates"
},
{
507
,
"Insufficient Storage"
},
{
508
,
"Loop Detected (WebDAV)"
},
{
510
,
"Not Extended"
},
{
511
,
"Network Authentication Required"
},
{
0
,
NULL
}
{
HTTP_CODE_CONTINUE
,
"Continue"
},
{
HTTP_CODE_SWITCHING_PROTOCOL
,
"Switching Protocol"
},
{
HTTP_CODE_PROCESSING
,
"Processing (WebDAV)"
},
{
HTTP_CODE_EARLY_HINTS
,
"Early Hints"
},
{
HTTP_CODE_OK
,
"OK"
},
{
HTTP_CODE_CREATED
,
"Created"
},
{
HTTP_CODE_ACCEPTED
,
"Accepted"
},
{
HTTP_CODE_NON_AUTHORITATIVE_INFO
,
"Non-Authoritative Information"
},
{
HTTP_CODE_NO_CONTENT
,
"No Content"
},
{
HTTP_CODE_RESET_CONTENT
,
"Reset Content"
},
{
HTTP_CODE_PARTIAL_CONTENT
,
"Partial Content"
},
{
HTTP_CODE_MULTI_STATUS
,
"Multi-Status (WebDAV)"
},
{
HTTP_CODE_ALREADY_REPORTED
,
"Already Reported (WebDAV)"
},
{
HTTP_CODE_IM_USED
,
"IM Used (HTTP Delta encoding)"
},
{
HTTP_CODE_MULTIPLE_CHOICE
,
"Multiple Choice"
},
{
HTTP_CODE_MOVED_PERMANENTLY
,
"Moved Permanently"
},
{
HTTP_CODE_FOUND
,
"Found"
},
{
HTTP_CODE_SEE_OTHER
,
"See Other"
},
{
HTTP_CODE_NOT_MODIFIED
,
"Not Modified"
},
{
HTTP_CODE_USE_PROXY
,
"Use Proxy"
},
{
HTTP_CODE_UNUSED
,
"unused"
},
{
HTTP_CODE_TEMPORARY_REDIRECT
,
"Temporary Redirect"
},
{
HTTP_CODE_PERMANENT_REDIRECT
,
"Permanent Redirect"
},
{
HTTP_CODE_BAD_REQUEST
,
"Bad Request"
},
{
HTTP_CODE_UNAUTHORIZED
,
"Unauthorized"
},
{
HTTP_CODE_PAYMENT_REQUIRED
,
"Payment Required"
},
{
HTTP_CODE_FORBIDDEN
,
"Forbidden"
},
{
HTTP_CODE_NOT_FOUND
,
"Not Found"
},
{
HTTP_CODE_METHOD_NOT_ALLOWED
,
"Method Not Allowed"
},
{
HTTP_CODE_NOT_ACCEPTABLE
,
"Not Acceptable"
},
{
HTTP_CODE_PROXY_AUTH_REQUIRED
,
"Proxy Authentication Required"
},
{
HTTP_CODE_REQUEST_TIMEOUT
,
"Request Timeout"
},
{
HTTP_CODE_CONFLICT
,
"Conflict"
},
{
HTTP_CODE_GONE
,
"Gone"
},
{
HTTP_CODE_LENGTH_REQUIRED
,
"Length Required"
},
{
HTTP_CODE_PRECONDITION_FAILED
,
"Precondition Failed"
},
{
HTTP_CODE_PAYLOAD_TOO_LARGE
,
"Payload Too Large"
},
{
HTTP_CODE_URI_TOO_LARGE
,
"URI Too Long"
},
{
HTTP_CODE_UNSUPPORTED_MEDIA_TYPE
,
"Unsupported Media Type"
},
{
HTTP_CODE_RANGE_NOT_SATISFIABLE
,
"Range Not Satisfiable"
},
{
HTTP_CODE_EXPECTATION_FAILED
,
"Expectation Failed"
},
{
HTTP_CODE_IM_A_TEAPOT
,
"I'm a teapot"
},
{
HTTP_CODE_MISDIRECTED_REQUEST
,
"Misdirected Request"
},
{
HTTP_CODE_UNPROCESSABLE_ENTITY
,
"Unprocessable Entity (WebDAV)"
},
{
HTTP_CODE_LOCKED
,
"Locked (WebDAV)"
},
{
HTTP_CODE_FAILED_DEPENDENCY
,
"Failed Dependency (WebDAV)"
},
{
HTTP_CODE_TOO_EARLY
,
"Too Early"
},
{
HTTP_CODE_UPGRADE_REQUIRED
,
"Upgrade Required"
},
{
HTTP_CODE_PRECONDITION_REQUIRED
,
"Precondition Required"
},
{
HTTP_CODE_TOO_MANY_REQUESTS
,
"Too Many Requests"
},
{
HTTP_CODE_REQ_HDR_FIELDS_TOO_LARGE
,
"Request Header Fields Too Large"
},
{
HTTP_CODE_UNAVAIL_4_LEGAL_REASONS
,
"Unavailable For Legal Reasons"
},
{
HTTP_CODE_INTERNAL_SERVER_ERROR
,
"Internal Server Error"
},
{
HTTP_CODE_NOT_IMPLEMENTED
,
"Not Implemented"
},
{
HTTP_CODE_BAD_GATEWAY
,
"Bad Gateway"
},
{
HTTP_CODE_SERVICE_UNAVAILABLE
,
"Service Unavailable"
},
{
HTTP_CODE_GATEWAY_TIMEOUT
,
"Gateway Timeout"
},
{
HTTP_CODE_HTTP_VER_NOT_SUPPORTED
,
"HTTP Version Not Supported"
},
{
HTTP_CODE_VARIANT_ALSO_NEGOTIATES
,
"Variant Also Negotiates"
},
{
HTTP_CODE_INSUFFICIENT_STORAGE
,
"Insufficient Storage"
},
{
HTTP_CODE_LOOP_DETECTED
,
"Loop Detected (WebDAV)"
},
{
HTTP_CODE_NOT_EXTENDED
,
"Not Extended"
},
{
HTTP_CODE_NETWORK_AUTH_REQUIRED
,
"Network Authentication Required"
},
{
0
,
NULL
}
};
char
*
httpGetStatusDesc
(
int32_t
statusCode
)
{
...
...
@@ -101,13 +101,17 @@ char *httpGetStatusDesc(int32_t statusCode) {
}
static
void
httpCleanupString
(
HttpString
*
str
)
{
free
(
str
->
str
);
str
->
str
=
NULL
;
str
->
pos
=
0
;
str
->
size
=
0
;
if
(
str
->
str
)
{
free
(
str
->
str
);
str
->
str
=
NULL
;
str
->
pos
=
0
;
str
->
size
=
0
;
}
}
static
int32_t
httpAppendString
(
HttpString
*
str
,
const
char
*
s
,
int32_t
len
)
{
char
*
new_str
=
NULL
;
if
(
str
->
size
==
0
)
{
str
->
pos
=
0
;
str
->
size
=
len
+
1
;
...
...
@@ -115,7 +119,16 @@ static int32_t httpAppendString(HttpString *str, const char *s, int32_t len) {
}
else
if
(
str
->
pos
+
len
+
1
>=
str
->
size
)
{
str
->
size
+=
len
;
str
->
size
*=
4
;
str
->
str
=
realloc
(
str
->
str
,
str
->
size
);
new_str
=
realloc
(
str
->
str
,
str
->
size
);
if
(
new_str
==
NULL
&&
str
->
str
)
{
// if str->str was not NULL originally,
// the old allocated memory was left unchanged,
// see man 3 realloc
free
(
str
->
str
);
}
str
->
str
=
new_str
;
}
else
{
}
...
...
@@ -163,9 +176,9 @@ static int32_t httpOnRequestLine(HttpParser *pParser, char *method, char *target
// parse decode method
for
(
int32_t
i
=
0
;
i
<
tsHttpServer
.
methodScannerLen
;
i
++
)
{
HttpDecodeMethod
*
method
=
tsHttpServer
.
methodScanner
[
i
];
if
(
strcmp
(
method
->
module
,
pParser
->
path
[
0
].
str
)
==
0
)
{
pContext
->
decodeMethod
=
method
;
HttpDecodeMethod
*
_
method
=
tsHttpServer
.
methodScanner
[
i
];
if
(
strcmp
(
_
method
->
module
,
pParser
->
path
[
0
].
str
)
==
0
)
{
pContext
->
decodeMethod
=
_
method
;
break
;
}
}
...
...
@@ -317,7 +330,7 @@ static int32_t httpOnParseHeaderField(HttpParser *parser, const char *key, const
static
int32_t
httpOnBody
(
HttpParser
*
parser
,
const
char
*
chunk
,
int32_t
len
)
{
HttpContext
*
pContext
=
parser
->
pContext
;
HttpString
*
buf
=
&
parser
->
body
;
HttpString
*
buf
=
&
parser
->
body
;
if
(
parser
->
parseCode
!=
TSDB_CODE_SUCCESS
)
return
-
1
;
if
(
buf
->
size
<=
0
)
{
...
...
@@ -326,6 +339,7 @@ static int32_t httpOnBody(HttpParser *parser, const char *chunk, int32_t len) {
}
int32_t
newSize
=
buf
->
pos
+
len
+
1
;
char
*
newStr
=
NULL
;
if
(
newSize
>=
buf
->
size
)
{
if
(
buf
->
size
>=
HTTP_BUFFER_SIZE
)
{
httpError
(
"context:%p, fd:%d, failed parse body, exceeding buffer size %d"
,
pContext
,
pContext
->
fd
,
buf
->
size
);
...
...
@@ -336,7 +350,12 @@ static int32_t httpOnBody(HttpParser *parser, const char *chunk, int32_t len) {
newSize
=
MAX
(
newSize
,
HTTP_BUFFER_INIT
);
newSize
*=
4
;
newSize
=
MIN
(
newSize
,
HTTP_BUFFER_SIZE
);
buf
->
str
=
realloc
(
buf
->
str
,
newSize
);
newStr
=
realloc
(
buf
->
str
,
newSize
);
if
(
newStr
==
NULL
&&
buf
->
str
)
{
free
(
buf
->
str
);
}
buf
->
str
=
newStr
;
buf
->
size
=
newSize
;
if
(
buf
->
str
==
NULL
)
{
...
...
@@ -374,13 +393,20 @@ static HTTP_PARSER_STATE httpTopStack(HttpParser *parser) {
static
int32_t
httpPushStack
(
HttpParser
*
parser
,
HTTP_PARSER_STATE
state
)
{
HttpStack
*
stack
=
&
parser
->
stacks
;
int8_t
*
newStacks
=
NULL
;
if
(
stack
->
size
==
0
)
{
stack
->
pos
=
0
;
stack
->
size
=
32
;
stack
->
stacks
=
malloc
(
stack
->
size
*
sizeof
(
int8_t
));
}
else
if
(
stack
->
pos
+
1
>
stack
->
size
)
{
stack
->
size
*=
2
;
stack
->
stacks
=
realloc
(
stack
->
stacks
,
stack
->
size
*
sizeof
(
int8_t
));
newStacks
=
realloc
(
stack
->
stacks
,
stack
->
size
*
sizeof
(
int8_t
));
if
(
newStacks
==
NULL
&&
stack
->
stacks
)
{
free
(
stack
->
stacks
);
}
stack
->
stacks
=
newStacks
;
}
else
{
}
...
...
@@ -552,7 +578,7 @@ static int32_t httpParserOnBegin(HttpParser *parser, HTTP_PARSER_STATE state, co
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
break
;
}
httpPopStack
(
parser
);
...
...
@@ -561,7 +587,7 @@ static int32_t httpParserOnBegin(HttpParser *parser, HTTP_PARSER_STATE state, co
}
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
}
while
(
0
);
return
ok
;
}
...
...
@@ -599,7 +625,7 @@ static int32_t httpParserOnRquestOrResponse(HttpParser *parser, HTTP_PARSER_STAT
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
}
while
(
0
);
return
ok
;
}
...
...
@@ -612,7 +638,7 @@ static int32_t httpParserOnMethod(HttpParser *parser, HTTP_PARSER_STATE state, c
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
break
;
}
break
;
...
...
@@ -621,7 +647,7 @@ static int32_t httpParserOnMethod(HttpParser *parser, HTTP_PARSER_STATE state, c
if
(
!
parser
->
method
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_METHOD_FAILED
);
break
;
}
else
{
httpTrace
(
"context:%p, fd:%d, httpMethod:%s"
,
pContext
,
pContext
->
fd
,
parser
->
method
);
...
...
@@ -641,7 +667,7 @@ static int32_t httpParserOnTarget(HttpParser *parser, HTTP_PARSER_STATE state, c
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_TARGET_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_TARGET_FAILED
);
break
;
}
break
;
...
...
@@ -650,7 +676,7 @@ static int32_t httpParserOnTarget(HttpParser *parser, HTTP_PARSER_STATE state, c
if
(
!
parser
->
target
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_TARGET_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_TARGET_FAILED
);
break
;
}
httpClearString
(
&
parser
->
str
);
...
...
@@ -670,13 +696,13 @@ static int32_t httpParserOnVersion(HttpParser *parser, HTTP_PARSER_STATE state,
if
(
prefix
[
parser
->
str
.
pos
]
!=
c
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
break
;
}
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
break
;
}
break
;
...
...
@@ -685,14 +711,14 @@ static int32_t httpParserOnVersion(HttpParser *parser, HTTP_PARSER_STATE state,
if
(
c
!=
'0'
&&
c
!=
'1'
&&
c
!=
'2'
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
break
;
}
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
break
;
}
...
...
@@ -709,7 +735,7 @@ static int32_t httpParserOnVersion(HttpParser *parser, HTTP_PARSER_STATE state,
if
(
!
parser
->
version
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_VERSION_FAILED
);
break
;
}
...
...
@@ -739,11 +765,20 @@ static int32_t httpParserOnSp(HttpParser *parser, HTTP_PARSER_STATE state, const
}
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_SP_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_SP_FAILED
);
}
while
(
0
);
return
ok
;
}
static
int32_t
httpParserOnOptionalSp
(
HttpParser
*
parser
,
HTTP_PARSER_STATE
state
,
const
char
c
,
int32_t
*
again
)
{
int32_t
ok
=
0
;
if
(
c
!=
' '
)
{
*
again
=
1
;
httpPopStack
(
parser
);
}
return
ok
;
}
static
int32_t
httpParserOnStatusCode
(
HttpParser
*
parser
,
HTTP_PARSER_STATE
state
,
const
char
c
,
int32_t
*
again
)
{
HttpContext
*
pContext
=
parser
->
pContext
;
int32_t
ok
=
0
;
...
...
@@ -752,7 +787,7 @@ static int32_t httpParserOnStatusCode(HttpParser *parser, HTTP_PARSER_STATE stat
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_STATUS_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_STATUS_FAILED
);
break
;
}
if
(
parser
->
str
.
pos
<
3
)
break
;
...
...
@@ -764,7 +799,7 @@ static int32_t httpParserOnStatusCode(HttpParser *parser, HTTP_PARSER_STATE stat
}
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_STATUS_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_STATUS_FAILED
);
}
while
(
0
);
return
ok
;
}
...
...
@@ -778,7 +813,7 @@ static int32_t httpParserOnReasonPhrase(HttpParser *parser, HTTP_PARSER_STATE st
if
(
!
parser
->
reasonPhrase
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_PHRASE_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_PHRASE_FAILED
);
break
;
}
ok
=
httpOnStatusLine
(
parser
,
parser
->
statusCode
,
parser
->
reasonPhrase
);
...
...
@@ -790,7 +825,7 @@ static int32_t httpParserOnReasonPhrase(HttpParser *parser, HTTP_PARSER_STATE st
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_PHRASE_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_PHRASE_FAILED
);
break
;
}
}
while
(
0
);
...
...
@@ -802,7 +837,7 @@ static int32_t httpParserPostProcess(HttpParser *parser) {
if
(
parser
->
gzip
)
{
if
(
ehttp_gzip_finish
(
parser
->
gzip
))
{
httpError
(
"context:%p, fd:%d, gzip failed"
,
pContext
,
pContext
->
fd
);
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_FINISH_GZIP_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_FINISH_GZIP_FAILED
);
return
-
1
;
}
}
...
...
@@ -819,13 +854,13 @@ static int32_t httpParserOnCrlf(HttpParser *parser, HTTP_PARSER_STATE state, con
if
(
s
[
parser
->
str
.
pos
]
!=
c
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_CRLF_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_CRLF_FAILED
);
break
;
}
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_CRLF_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_CRLF_FAILED
);
break
;
}
if
(
parser
->
str
.
pos
==
len
)
{
...
...
@@ -862,18 +897,18 @@ static int32_t httpParserOnHeader(HttpParser *parser, HTTP_PARSER_STATE state, c
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_HEADER_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_HEADER_FAILED
);
break
;
}
httpPushStack
(
parser
,
HTTP_PARSER_CRLF
);
httpPushStack
(
parser
,
HTTP_PARSER_HEADER_VAL
);
httpPushStack
(
parser
,
HTTP_PARSER_SP
);
httpPushStack
(
parser
,
HTTP_PARSER_
OPTIONAL_
SP
);
httpPushStack
(
parser
,
HTTP_PARSER_HEADER_KEY
);
break
;
}
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_HEADER_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_HEADER_FAILED
);
}
while
(
0
);
return
ok
;
}
...
...
@@ -886,7 +921,7 @@ static int32_t httpParserOnHeaderKey(HttpParser *parser, HTTP_PARSER_STATE state
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_HEADER_KEY_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_HEADER_KEY_FAILED
);
break
;
}
break
;
...
...
@@ -896,7 +931,7 @@ static int32_t httpParserOnHeaderKey(HttpParser *parser, HTTP_PARSER_STATE state
if
(
!
parser
->
key
)
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_HEADER_KEY_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_HEADER_KEY_FAILED
);
break
;
}
httpClearString
(
&
parser
->
str
);
...
...
@@ -905,7 +940,7 @@ static int32_t httpParserOnHeaderKey(HttpParser *parser, HTTP_PARSER_STATE state
}
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_HEADER_KEY_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_HEADER_KEY_FAILED
);
}
while
(
0
);
return
ok
;
}
...
...
@@ -919,7 +954,7 @@ static int32_t httpParserOnHeaderVal(HttpParser *parser, HTTP_PARSER_STATE state
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
parser
->
parseCode
=
TSDB_CODE_HTTP_PARSE_HEADER_VAL_FAILED
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_HEADER_VAL_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_HEADER_VAL_FAILED
);
break
;
}
break
;
...
...
@@ -948,7 +983,7 @@ static int32_t httpParserOnChunkSize(HttpParser *parser, HTTP_PARSER_STATE state
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_CHUNK_SIZE_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_CHUNK_SIZE_FAILED
);
break
;
}
break
;
...
...
@@ -982,7 +1017,7 @@ static int32_t httpParserOnChunkSize(HttpParser *parser, HTTP_PARSER_STATE state
}
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
400
,
TSDB_CODE_HTTP_PARSE_CHUNK_SIZE_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_BAD_REQUEST
,
TSDB_CODE_HTTP_PARSE_CHUNK_SIZE_FAILED
);
}
while
(
0
);
return
ok
;
}
...
...
@@ -994,7 +1029,7 @@ static int32_t httpParserOnChunk(HttpParser *parser, HTTP_PARSER_STATE state, co
if
(
httpAppendString
(
&
parser
->
str
,
&
c
,
1
))
{
httpError
(
"context:%p, fd:%d, parser state:%d, char:[%c]%02x, oom"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_CHUNK_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_CHUNK_FAILED
);
break
;
}
++
parser
->
receivedSize
;
...
...
@@ -1005,7 +1040,7 @@ static int32_t httpParserOnChunk(HttpParser *parser, HTTP_PARSER_STATE state, co
if
(
ehttp_gzip_write
(
parser
->
gzip
,
parser
->
str
.
str
,
parser
->
str
.
pos
))
{
httpError
(
"context:%p, fd:%d, gzip failed"
,
pContext
,
pContext
->
fd
);
ok
=
-
1
;
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_CHUNK_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_CHUNK_FAILED
);
break
;
}
}
else
{
...
...
@@ -1027,7 +1062,7 @@ static int32_t httpParserOnEnd(HttpParser *parser, HTTP_PARSER_STATE state, cons
do
{
ok
=
-
1
;
httpError
(
"context:%p, fd:%d, parser state:%d, unexpected char:[%c]%02x"
,
pContext
,
pContext
->
fd
,
state
,
c
,
c
);
httpOnError
(
parser
,
507
,
TSDB_CODE_HTTP_PARSE_END_FAILED
);
httpOnError
(
parser
,
HTTP_CODE_INSUFFICIENT_STORAGE
,
TSDB_CODE_HTTP_PARSE_END_FAILED
);
}
while
(
0
);
return
ok
;
}
...
...
@@ -1061,6 +1096,10 @@ static int32_t httpParseChar(HttpParser *parser, const char c, int32_t *again) {
ok
=
httpParserOnSp
(
parser
,
state
,
c
,
again
);
break
;
}
if
(
state
==
HTTP_PARSER_OPTIONAL_SP
)
{
ok
=
httpParserOnOptionalSp
(
parser
,
state
,
c
,
again
);
break
;
}
if
(
state
==
HTTP_PARSER_STATUS_CODE
)
{
ok
=
httpParserOnStatusCode
(
parser
,
state
,
c
,
again
);
break
;
...
...
@@ -1104,7 +1143,7 @@ static int32_t httpParseChar(HttpParser *parser, const char c, int32_t *again) {
ok
=
-
1
;
httpError
(
"context:%p, fd:%d, unknown parse state:%d"
,
pContext
,
pContext
->
fd
,
state
);
httpOnError
(
parser
,
500
,
TSDB_CODE_HTTP_PARSE_INVALID_STATE
);
httpOnError
(
parser
,
HTTP_CODE_INTERNAL_SERVER_ERROR
,
TSDB_CODE_HTTP_PARSE_INVALID_STATE
);
}
while
(
0
);
if
(
ok
==
-
1
)
{
...
...
@@ -1115,7 +1154,7 @@ static int32_t httpParseChar(HttpParser *parser, const char c, int32_t *again) {
if
(
ok
==
-
2
)
{
ok
=
-
1
;
httpError
(
"context:%p, fd:%d, failed to parse, invalid state"
,
pContext
,
pContext
->
fd
);
httpOnError
(
parser
,
500
,
TSDB_CODE_HTTP_PARSE_ERROR_STATE
);
httpOnError
(
parser
,
HTTP_CODE_INTERNAL_SERVER_ERROR
,
TSDB_CODE_HTTP_PARSE_ERROR_STATE
);
}
return
ok
;
...
...
src/plugins/http/src/httpUtil.c
浏览文件 @
4e9fb447
...
...
@@ -188,13 +188,17 @@ bool httpMallocMultiCmds(HttpContext *pContext, int32_t cmdSize, int32_t bufferS
bool
httpReMallocMultiCmdsSize
(
HttpContext
*
pContext
,
int32_t
cmdSize
)
{
HttpSqlCmds
*
multiCmds
=
pContext
->
multiCmds
;
if
(
cmdSize
>
HTTP_MAX_CMD_SIZE
)
{
if
(
cmdSize
<=
0
&&
cmdSize
>
HTTP_MAX_CMD_SIZE
)
{
httpError
(
"context:%p, fd:%d, user:%s, mulitcmd size:%d large then %d"
,
pContext
,
pContext
->
fd
,
pContext
->
user
,
cmdSize
,
HTTP_MAX_CMD_SIZE
);
return
false
;
}
multiCmds
->
cmds
=
(
HttpSqlCmd
*
)
realloc
(
multiCmds
->
cmds
,
(
size_t
)
cmdSize
*
sizeof
(
HttpSqlCmd
));
HttpSqlCmd
*
new_cmds
=
(
HttpSqlCmd
*
)
realloc
(
multiCmds
->
cmds
,
(
size_t
)
cmdSize
*
sizeof
(
HttpSqlCmd
));
if
(
new_cmds
==
NULL
&&
multiCmds
->
cmds
)
{
free
(
multiCmds
->
cmds
);
}
multiCmds
->
cmds
=
new_cmds
;
if
(
multiCmds
->
cmds
==
NULL
)
{
httpError
(
"context:%p, fd:%d, user:%s, malloc cmds:%d error"
,
pContext
,
pContext
->
fd
,
pContext
->
user
,
cmdSize
);
return
false
;
...
...
@@ -208,13 +212,17 @@ bool httpReMallocMultiCmdsSize(HttpContext *pContext, int32_t cmdSize) {
bool
httpReMallocMultiCmdsBuffer
(
HttpContext
*
pContext
,
int32_t
bufferSize
)
{
HttpSqlCmds
*
multiCmds
=
pContext
->
multiCmds
;
if
(
bufferSize
>
HTTP_MAX_BUFFER_SIZE
)
{
if
(
bufferSize
<=
0
||
bufferSize
>
HTTP_MAX_BUFFER_SIZE
)
{
httpError
(
"context:%p, fd:%d, user:%s, mulitcmd buffer size:%d large then %d"
,
pContext
,
pContext
->
fd
,
pContext
->
user
,
bufferSize
,
HTTP_MAX_BUFFER_SIZE
);
return
false
;
}
multiCmds
->
buffer
=
(
char
*
)
realloc
(
multiCmds
->
buffer
,
(
size_t
)
bufferSize
);
char
*
new_buffer
=
(
char
*
)
realloc
(
multiCmds
->
buffer
,
(
size_t
)
bufferSize
);
if
(
new_buffer
==
NULL
&&
multiCmds
->
buffer
)
{
free
(
multiCmds
->
buffer
);
}
multiCmds
->
buffer
=
new_buffer
;
if
(
multiCmds
->
buffer
==
NULL
)
{
httpError
(
"context:%p, fd:%d, user:%s, malloc buffer:%d error"
,
pContext
,
pContext
->
fd
,
pContext
->
user
,
bufferSize
);
return
false
;
...
...
@@ -237,6 +245,11 @@ void httpFreeMultiCmds(HttpContext *pContext) {
JsonBuf
*
httpMallocJsonBuf
(
HttpContext
*
pContext
)
{
if
(
pContext
->
jsonBuf
==
NULL
)
{
pContext
->
jsonBuf
=
(
JsonBuf
*
)
malloc
(
sizeof
(
JsonBuf
));
if
(
pContext
->
jsonBuf
==
NULL
)
{
return
NULL
;
}
memset
(
pContext
->
jsonBuf
,
0
,
sizeof
(
JsonBuf
));
}
if
(
!
pContext
->
jsonBuf
->
pContext
)
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录