1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
use std::str::FromStr;
use std::convert::TryFrom;
use std::io::{Error, Result, ErrorKind};
use bytes::BufMut;
use mime::{MULTIPART,
FORM_DATA,
BOUNDARY,
AUDIO,
VIDEO,
IMAGE,
FONT,
APPLICATION,
OCTET_STREAM,
PDF,
Mime};
use twoway::{find_bytes, rfind_bytes};
use httparse::{EMPTY_HEADER, parse_headers};
use https::{header::{CONTENT_TYPE, CONTENT_DISPOSITION, HeaderName, HeaderValue}};
use futures::future::{FutureExt, LocalBoxFuture};
use tcp::Socket;
use pi_handler::SGenType;
use crate::{gateway::GatewayContext,
middleware::{MiddlewareResult, Middleware},
request::HttpRequest,
response::HttpResponse};
///
/// 多部分请求分隔符通用前后缀
///
const MULTI_PARTS_COMMON_PREFIX_SUFFIX_BIN: &str = "--";
///
/// 多部分请求换行符
///
const MULTI_PARTS_LINE_BREAK: &str = "\r\n";
///
/// 多部分的参数分隔符
///
const MULTI_PARTS_PARAM_SPILT_CHAR: &str = ";";
///
/// 多部分的键值对分隔符
///
const MULTI_PARTS_PAIR_SPILT_CHAR: &str = "=";
///
/// 需要过滤的无效字符集
///
const MULTI_PARTS_FILTER_CHARS: &[char] = &[' ', '\t', '\"'];
///
/// 多部分请求时允许的最大Http头数量
///
const MAX_MUTIL_PARTS_HTTP_HEADER_LIMIT: usize = 8;
///
/// 特殊的Mime子类型
///
const X_MSDOWNLOAD_MIME_SUBTYPE: &str = "x-msdownload";
///
/// 多部分请求的表单参数名
///
const MULTI_PARTS_NAME_PARAM: &str = "name";
const MULTI_PARTS_FILE_NAME_PARAM: &str = "filename";
///
/// Http请求的多部分请求体分析器
///
pub struct MutilParts {
block_size: usize, //每次读取的请求体块大小
}
unsafe impl Send for MutilParts {}
unsafe impl Sync for MutilParts {}
impl<S: Socket> Middleware<S, GatewayContext> for MutilParts {
fn request<'a>(&'a self, context: &'a mut GatewayContext, req: HttpRequest<S>)
-> LocalBoxFuture<'a, MiddlewareResult<S>> {
let block_size = self.block_size;
let mut request = req;
let future = async move {
if let Some(content_type) = request.headers().get(CONTENT_TYPE) {
if let Ok(str) = content_type.to_str() {
if let Ok(mime) = Mime::from_str(str) {
if mime.type_() == MULTIPART && mime.subtype() == FORM_DATA {
//当前请求体使用了多部分请求体,则分析,并写入参数表
if let Some(param) = mime.get_param(BOUNDARY) {
//获取本次Http多部分请求体的分隔符
let boundary_str = (MULTI_PARTS_COMMON_PREFIX_SUFFIX_BIN.to_string() + param.as_str() + MULTI_PARTS_LINE_BREAK);
let boundary = boundary_str.as_bytes();
let boundary_end_bin = [MULTI_PARTS_COMMON_PREFIX_SUFFIX_BIN.as_bytes(),
param.as_str().as_bytes(), MULTI_PARTS_COMMON_PREFIX_SUFFIX_BIN.as_bytes(), MULTI_PARTS_LINE_BREAK.as_bytes()].concat();
let boundary_end = boundary_end_bin.as_slice();
loop {
if let Some(part) = request.next_body(block_size).await {
//读取到指定块大小的下个部分的请求体
let bin = part.as_ref();
match parse_part(context, boundary, bin.as_ref()) {
Err(e) => {
//解析部分数据时错误,则抛出错误
return MiddlewareResult::Throw(e);
},
Ok(_) => {
if check_part_end(bin, boundary_end).is_some() {
//已读取到所有多部分请求体,则退出多部分的读取
break;
} else {
//继续读取请求体
continue;
}
},
}
}
//退出多部分的读取
break;
}
//完成请求体的剩余部分的处理
if let Err(e) = parse_part_end(context,
param.as_str().as_bytes(),
boundary_end) {
//解析部分数据时错误,则抛出错误
return MiddlewareResult::Throw(e);
}
}
}
}
}
}
//继续请求处理
MiddlewareResult::ContinueRequest(request)
};
future.boxed_local()
}
fn response<'a>(&'a self,
_context: &'a mut GatewayContext,
req: HttpRequest<S>,
resp: HttpResponse)
-> LocalBoxFuture<'a, MiddlewareResult<S>> {
let future = async move {
//继续响应处理
MiddlewareResult::ContinueResponse((req, resp))
};
future.boxed_local()
}
}
impl MutilParts {
/// 构建指定块大小的Http多部分请求体分析器
pub fn with(block_size: usize) -> Self {
MutilParts {
block_size,
}
}
}
// 检查指定的请求体数据中是否有多部分请求的结尾部分,如果有则返回结尾标记的位置
fn check_part_end<'a>(buf: &'a [u8],
boundary_end: &'a [u8]) -> Option<usize> {
rfind_bytes(buf, boundary_end)
}
// 解析二进制数据,从中分析出多部分请求中的部分,中间数据存储在当前Http连接的网关上下文中,返回false,表示没有分析到完整的部分,需要继续读取数据后再次解析,否则返回已解析的部分
fn parse_part<'a>(context: &'a mut GatewayContext,
boundary: &'a [u8],
mut bin: &'a [u8]) -> Result<bool> {
if let Some(mut part_buf) = context.take_part_buf() {
//上次有未解析完的部分数据,则与本次的部分数据合并,并继续解析
part_buf.put(bin);
return parse_part(context, boundary, &part_buf[..]);
}
let mut offset;
let mut r = Ok(false); //是否已解析
loop {
if let Some(index) = find_bytes(bin, boundary) {
//查找到指定boundary分隔的负载,则继续查找负载
if let Err(e) = parse_part_headers_body(context, &bin[0..index]) {
return Err(e);
}
r = Ok(true); //设置为已解析
offset = index + boundary.len();
if offset >= bin.len() {
//已经解析到数据尾,则结束本次解析
return r;
}
//继续解析剩余数据
bin = &bin[(index + boundary.len())..];
} else {
//查找不到指定boundary分隔的负载,则中止本次解析
context.push_part_buf(bin); //加入请求体未解析部分
return r;
}
}
}
// 解析二进制数据,从中分析出多部分请求的结尾部分
fn parse_part_end<'a>(context: &'a mut GatewayContext,
boundary: &'a [u8],
boundary_end: &'a [u8]) -> Result<()> {
if let Some(mut part_buf) = context.take_part_buf() {
//解析剩余的非结尾部分
let boundary_bin = [MULTI_PARTS_COMMON_PREFIX_SUFFIX_BIN.as_bytes(),
boundary, MULTI_PARTS_LINE_BREAK.as_bytes()].concat();
let boundary_ = boundary_bin.as_slice();
if let Err(e) = parse_part(context, boundary_, &part_buf[..]) {
return Err(e);
}
}
if let Some(mut part_buf) = context.take_part_buf() {
//解析结尾部分
if let Some(index) = check_part_end(&part_buf[..], boundary_end) {
//查找到指定boundary分隔的结尾负载
if let Err(e) = parse_part_headers_body(context, &part_buf[0..index]) {
return Err(e);
}
}
}
Ok(())
}
// 解析部分数据的头和体
fn parse_part_headers_body<'a>(context: &'a mut GatewayContext, part: &'a [u8]) -> Result<()> {
if part.len() == 0 {
//部分数据长度为0,则忽略
return Ok(());
}
let mut headers = [EMPTY_HEADER; MAX_MUTIL_PARTS_HTTP_HEADER_LIMIT];
match parse_headers(part, &mut headers) {
Err(e) => {
//解析部分数据的头错误,则立即返回错误原因
Err(Error::new(ErrorKind::Other,
format!("Parse multi parts headers failed, reason: {:?}",
e)))
},
Ok(status) if status.is_complete() => {
//解析部分数据的头完成
let (offset, headers) = status.unwrap();
//将头数据写入参数表
let mut name_key = None;
let context_parts = context.as_mut_parts();
for header in headers {
match HeaderName::try_from(header.name) {
Err(e) => {
return Err(Error::new(ErrorKind::InvalidData,
format!("Parse multi parts headers name failed, reason: {:?}",
e)));
},
Ok(key) => {
match HeaderValue::from_bytes(header.value) {
Err(e) => {
return Err(Error::new(ErrorKind::InvalidData,
format!("Parse multi parts headers value failed, reason: {:?}",
e)));
},
Ok(value) => {
//构建值成功
if let Ok(value_str) = value.to_str() {
if key == CONTENT_DISPOSITION {
//部分数据默认的头
let params: Vec<&str> = value_str.split(MULTI_PARTS_PARAM_SPILT_CHAR).collect();
for param in params {
let pair: Vec<&str> = param.split(MULTI_PARTS_PAIR_SPILT_CHAR).collect();
if let Some(param_key) = pair.get(0) {
if let Some(param_val) = pair.get(1) {
//只解析键值对
let k = param_key.trim_matches(MULTI_PARTS_FILTER_CHARS);
let v = param_val.trim_matches(MULTI_PARTS_FILTER_CHARS);
match k {
MULTI_PARTS_NAME_PARAM => {
//有名为name的参数,则需要读取部分的体数据
name_key = Some(v.to_string());
},
MULTI_PARTS_FILE_NAME_PARAM => {
//有名为filename的参数,则写入网产在上下文的部分数据中
context_parts.insert(String::from_utf8_lossy(k.as_bytes()).to_string(), SGenType::Str(String::from_utf8_lossy(v.as_bytes()).to_string()));
},
_ => {
//其它参数,则忽略
continue;
}
}
}
}
}
} else if key == CONTENT_TYPE {
//表示当前部分的体数据有指定类型
if let Some(name_key) = name_key.take() {
if let Ok(mime) = Mime::from_str(value_str) {
if mime.type_() == AUDIO
|| mime.type_() == VIDEO
|| mime.type_() == IMAGE
|| mime.type_() == FONT
|| (mime.type_() == APPLICATION
&& (mime.subtype() == OCTET_STREAM || mime.subtype() == PDF || mime.subtype().as_str() == X_MSDOWNLOAD_MIME_SUBTYPE)) {
//写入二进制的体数据
context_parts.insert(name_key, SGenType::Bin(Vec::from(&part[offset..(part.len() - MULTI_PARTS_LINE_BREAK.len())])));
} else {
//写入文本的体数据
context_parts.insert(name_key, SGenType::Str(String::from_utf8_lossy(&part[offset..(part.len() - MULTI_PARTS_LINE_BREAK.len())]).to_string()));
}
}
}
}
}
},
}
},
}
}
if let Some(name_key) = name_key.take() {
//当前部分的体数据没有指定类型,则写入明文的体数据
context_parts.insert(name_key, SGenType::Str(String::from_utf8_lossy(&part[offset..(part.len() - MULTI_PARTS_LINE_BREAK.len())]).to_string()));
}
Ok(())
},
_ => {
//解析部分数据不完整,则立即返回错误原因
Err(Error::new(ErrorKind::Other,
"Parse multi parts headers failed, reason: part not enough"))
}
}
}