下面列出了怎么用 io.netty.handler.codec.http.multipart.InterfaceHttpData 的API类实例代码及写法,或者点击链接到github查看源代码。
private static Map<String,String> getAttribs(FullHttpRequest request) {
String header = HttpHeaders.getHeader(request, HttpHeaders.Names.CONTENT_TYPE);
if (HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED.equalsIgnoreCase(header)) {
Map<String,String> attribs = new HashMap<>();
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), request);
List<InterfaceHttpData> data = decoder.getBodyHttpDatas();
if (data != null) {
for (InterfaceHttpData datum : data) {
if (datum.getHttpDataType() == HttpDataType.Attribute) {
Attribute attribute = (Attribute)datum;
try {
attribs.put(attribute.getName(), attribute.getString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
return attribs;
}
}
return null;
}
private Map<String, List<String>> parsePostFormParameters(FullHttpRequest request) {
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), request);
Map<String, List<String>> attributes = new HashMap<String, List<String>>();
List<InterfaceHttpData> datas = decoder.getBodyHttpDatas();
for (InterfaceHttpData data : datas) {
if (data.getHttpDataType() == HttpDataType.Attribute) {
try {
String name = data.getName();
String value = ((Attribute) data).getString();
attributes.putIfAbsent(name, new ArrayList<String>());
attributes.get(name).add(value);
} catch (IOException e) {
LOGGER.error("Error getting HTTP attribute from POST request");
}
}
}
decoder.destroy();
return attributes;
}
@Nullable
public static String extractFormParam(HttpPostRequestDecoder decoder, String name, boolean required) throws HttpException {
InterfaceHttpData data = decoder.getBodyHttpData(name);
try {
String value = null;
if(data != null && data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
Attribute attribute = (Attribute) data;
value = attribute.getValue();
}
if(value == null && required) {
throw new HttpException(HttpResponseStatus.BAD_REQUEST.code());
}
return value;
} catch(IOException ioe) {
throw new HttpException(HttpResponseStatus.INTERNAL_SERVER_ERROR.code());
}
}
protected DFHttpMultiData(HttpPostRequestDecoder reqDecoder) {
this.reqDecoder = reqDecoder;
List<InterfaceHttpData> lsReqData = reqDecoder.getBodyHttpDatas();
if(lsReqData.isEmpty()){
lsData = null;
partNum = 0;
}else{
int tmpNum = 0;
lsData = new ArrayList<>(lsReqData.size());
for(InterfaceHttpData reqData : lsReqData){
if(reqData.getHttpDataType() == HttpDataType.FileUpload){
FileUpload fUp = (FileUpload) reqData;
String tmpFile = fUp.getFilename();
if(tmpFile == null || tmpFile.equals("")){
continue;
}
DFHttpData data = new DFHttpData(fUp);
lsData.add(data);
++tmpNum;
}
}
partNum = tmpNum;
}
}
/**
* Destroy the {@link HttpPostMultipartRequestDecoder} and release all it
* resources. After this method was called it is not possible to operate on it
* anymore.
*/
@Override
public void destroy() {
checkDestroyed();
cleanFiles();
destroyed = true;
if (undecodedChunk != null && undecodedChunk.refCnt() > 0) {
undecodedChunk.release();
undecodedChunk = null;
}
// release all data which was not yet pulled
for (int i = bodyListHttpDataRank; i < bodyListHttpData.size(); i++) {
InterfaceHttpData data = bodyListHttpData.get(i);
if (data.refCnt() > 0)
data.release();
}
}
private void parseHttpPostRequest(FullHttpRequest request) {
HttpPostRequestDecoder decoder = null;
try {
decoder = new HttpPostRequestDecoder(request);
for (InterfaceHttpData httpData : decoder.getBodyHttpDatas()) {
HttpDataType _type = httpData.getHttpDataType();
if (_type == HttpDataType.Attribute) {
Attribute attribute = (Attribute) httpData;
parseAttribute(attribute);
} else if (_type == HttpDataType.FileUpload) {
FileUpload upload = (FileUpload) httpData;
multipartFiles.add(MultipartFileFactory.create(upload));
}
}
} catch (Exception ex) {
LogUtils.warn(ex.getMessage());
} finally {
// 注意这个地方,一定要调用destroy方法,如果不调用会导致内存泄漏
if (decoder != null)
decoder.destroy();
}
}
/**
* request parameters put in {@link #parameters}
*
* @param req
*/
private void requestParametersHandler(HttpRequest req) {
if (req.method().equals(HttpMethod.POST)) {
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req);
try {
List<InterfaceHttpData> postList = decoder.getBodyHttpDatas();
for (InterfaceHttpData data : postList) {
List<String> values = new ArrayList<String>();
MixedAttribute value = (MixedAttribute) data;
value.setCharset(CharsetUtil.UTF_8);
values.add(value.getValue());
this.parameters.put(data.getName(), values);
}
} catch (Exception e) {
logger.error(e.getMessage());
}
}
}
@Test
public void getMultipartParts_works_as_expected_with_known_empty_data() {
// given
RequestInfoImpl<?> requestInfo = RequestInfoImpl.dummyInstanceForUnknownRequests();
Whitebox.setInternalState(requestInfo, "isMultipart", true);
Whitebox.setInternalState(requestInfo, "contentCharset", CharsetUtil.UTF_8);
Whitebox.setInternalState(requestInfo, "protocolVersion", HttpVersion.HTTP_1_1);
Whitebox.setInternalState(requestInfo, "method", HttpMethod.POST);
requestInfo.isCompleteRequestWithAllChunks = true;
requestInfo.rawContentBytes = null;
requestInfo.getHeaders().set("Content-Type", KNOWN_MULTIPART_DATA_CONTENT_TYPE_HEADER);
// when
List<InterfaceHttpData> result = requestInfo.getMultipartParts();
// then
assertThat(result, notNullValue());
assertThat(result.isEmpty(), is(true));
}
@Test(expected = IllegalStateException.class)
public void getMultipartParts_explodes_if_multipartData_had_been_released() {
// given
RequestInfoImpl<?> requestInfo = RequestInfoImpl.dummyInstanceForUnknownRequests();
Whitebox.setInternalState(requestInfo, "isMultipart", true);
Whitebox.setInternalState(requestInfo, "contentCharset", CharsetUtil.UTF_8);
Whitebox.setInternalState(requestInfo, "protocolVersion", HttpVersion.HTTP_1_1);
Whitebox.setInternalState(requestInfo, "method", HttpMethod.POST);
requestInfo.isCompleteRequestWithAllChunks = true;
requestInfo.rawContentBytes = KNOWN_MULTIPART_DATA_BODY.getBytes(CharsetUtil.UTF_8);
requestInfo.getHeaders().set("Content-Type", KNOWN_MULTIPART_DATA_CONTENT_TYPE_HEADER);
List<InterfaceHttpData> result = requestInfo.getMultipartParts();
assertThat(result, notNullValue());
assertThat(result.size(), is(1));
// expect
requestInfo.releaseMultipartData();
requestInfo.getMultipartParts();
fail("Expected an error, but none was thrown");
}
@Test
public void getMultipartParts_returns_data_from_multipartData() {
// given
RequestInfoImpl<?> requestInfo = RequestInfoImpl.dummyInstanceForUnknownRequests();
Whitebox.setInternalState(requestInfo, "isMultipart", true);
requestInfo.isCompleteRequestWithAllChunks = true;
HttpPostMultipartRequestDecoder multipartDataMock = mock(HttpPostMultipartRequestDecoder.class);
List<InterfaceHttpData> dataListMock = mock(List.class);
doReturn(dataListMock).when(multipartDataMock).getBodyHttpDatas();
requestInfo.multipartData = multipartDataMock;
// when
List<InterfaceHttpData> result = requestInfo.getMultipartParts();
// then
assertThat(result, is(dataListMock));
}
private void handleUploadMessage(io.netty.handler.codec.http.HttpMessage httpMsg, Message uploadMessage) throws IOException{
if (httpMsg instanceof HttpContent) {
HttpContent chunk = (HttpContent) httpMsg;
decoder.offer(chunk);
try {
while (decoder.hasNext()) {
InterfaceHttpData data = decoder.next();
if (data != null) {
try {
handleUploadFile(data, uploadMessage);
} finally {
data.release();
}
}
}
} catch (EndOfDataDecoderException e1) {
//ignore
}
if (chunk instanceof LastHttpContent) {
resetUpload();
}
}
}
/**
* request parameters put in {@link #parameters}
*
* @param req
*/
private void requestParametersHandler(HttpRequest req) {
if (req.method().equals(HttpMethod.POST)) {
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req);
try {
List<InterfaceHttpData> postList = decoder.getBodyHttpDatas();
for (InterfaceHttpData data : postList) {
List<String> values = new ArrayList<String>();
MixedAttribute value = (MixedAttribute) data;
value.setCharset(CharsetUtil.UTF_8);
values.add(value.getValue());
this.parameters.put(data.getName(), values);
}
} catch (Exception e) {
logger.error(e.getMessage());
}
}
}
/**
* Example of reading request by chunk and getting values from chunk to chunk
*/
private void readHttpDataChunkByChunk() {
try {
while (decoder.hasNext()) {
InterfaceHttpData data = decoder.next();
if (data != null) {
try {
// new value
writeHttpData(data);
} finally {
data.release();
}
}
}
} catch (EndOfDataDecoderException e1) {
// end
responseContent.append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n");
}
}
@Override
public Object get(ChannelHandlerContext ctx, URIDecoder uriDecoder) {
List<InterfaceHttpData> bodyHttpDatas = uriDecoder.getBodyHttpDatas();
if (bodyHttpDatas == null || bodyHttpDatas.size() == 0) {
return null;
}
for (InterfaceHttpData data : bodyHttpDatas) {
if (name.equals(data.getName())) {
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
Attribute attribute = (Attribute) data;
try {
return ReflectionUtil.castTo(type, attribute.getValue());
} catch (IOException e) {
log.error("Error getting form params. Reason : {}", e.getMessage(), e);
}
}
}
}
return null;
}
void copyHttpBodyData(FullHttpRequest fullHttpReq, MockHttpServletRequest servletRequest){
ByteBuf bbContent = fullHttpReq.content();
if(bbContent.hasArray()) {
servletRequest.setContent(bbContent.array());
} else {
if(fullHttpReq.getMethod().equals(HttpMethod.POST)){
HttpPostRequestDecoder decoderPostData = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), fullHttpReq);
String bbContentStr = bbContent.toString(Charset.forName(UTF_8));
servletRequest.setContent(bbContentStr.getBytes());
if( ! decoderPostData.isMultipart() ){
List<InterfaceHttpData> postDatas = decoderPostData.getBodyHttpDatas();
for (InterfaceHttpData postData : postDatas) {
if (postData.getHttpDataType() == HttpDataType.Attribute) {
Attribute attribute = (Attribute) postData;
try {
servletRequest.addParameter(attribute.getName(),attribute.getValue());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public void init(Channel channel, FullHttpRequest request, RouteResult<RouteAction> routeResult, boolean enableCookies) {
this.channel = channel;
this.request = request;
this.routeResult = routeResult;
this.enableCookies = enableCookies;
if (this.method() == HttpMethod.POST) {
try {
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(request);
decoder.offer(request);
List<InterfaceHttpData> paramsList = decoder.getBodyHttpDatas();
for (InterfaceHttpData httpData : paramsList) {
if (httpData.getHttpDataType() == HttpDataType.Attribute) {
Attribute data = (Attribute) httpData;
postMaps.put(data.getName(), data.getValue());
} else if (httpData.getHttpDataType() == HttpDataType.FileUpload) {
MixedFileUpload fileUpload = (MixedFileUpload) httpData;
this.fileUpload = fileUpload;
} else {
LOGGER.error("not support http data type. type={}", httpData.getHttpDataType());
}
}
} catch (Exception ex) {
LOGGER.error("{}", ex);
}
}
if (enableCookies) {
List<String> cookiesList = request.headers().getAll(HttpHeaderNames.COOKIE);
cookiesList.forEach(h -> ServerCookieDecoder.STRICT.decode(h).forEach(c -> cookieMaps.put(c.name(), c)));
}
}
@Override
public void sendResponse(FullHttpRequest req, ChannelHandlerContext ctx) throws Exception {
long startTime = System.nanoTime();
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req);
try {
String place = null;
int num = 0;
while(decoder.hasNext()) {
num++;
InterfaceHttpData httpData = decoder.next();
if(httpData.getHttpDataType() == HttpDataType.Attribute && httpData.getName().equalsIgnoreCase("place")) {
place = ((Attribute) httpData).getValue();
} else if(httpData.getHttpDataType() == HttpDataType.FileUpload) {
String camProtAddr = URLDecoder.decode(httpData.getName(), "UTF-8");
Device d = findCamera(camProtAddr);
if(d == null) {
UPLOAD_UNKNOWN.inc();
logger.warn("ignoring preview upload for non-existent camera {}", camProtAddr);
continue;
}
write(place, d, (FileUpload) httpData);
}
}
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
ChannelFuture future = ctx.writeAndFlush(response);
if(!HttpHeaders.isKeepAlive(req)) {
future.addListener(ChannelFutureListener.CLOSE);
}
UPLOAD_NUM.update(num);
UPLOAD_SUCCESS.update(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
} catch (Exception ex) {
UPLOAD_FAIL.update(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
} finally {
decoder.cleanFiles();
}
}
private static String formatContent(FullHttpRequest request) {
String header = HttpHeaders.getHeader(request, HttpHeaders.Names.CONTENT_TYPE);
StringBuffer bf = new StringBuffer();
if (HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED.equalsIgnoreCase(header)) {
HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(new DefaultHttpDataFactory(false), request);
List<InterfaceHttpData> data = decoder.getBodyHttpDatas();
if (data != null) {
for (InterfaceHttpData datum : data) {
if (datum.getHttpDataType() == HttpDataType.Attribute) {
Attribute attribute = (Attribute)datum;
try {
bf.append(attribute.getName()).append(" -> ").append(attribute.getString()).append("\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
else {
bf.append("[No Data]\n");
}
}
else if ("application/json".equalsIgnoreCase(header)) {
ByteBuf byteBuf = request.content();
byte[] bytes = new byte[byteBuf.readableBytes()];
byteBuf.readBytes(bytes);
String s = new String(bytes, StandardCharsets.UTF_8);
bf.append(s);
}
else {
bf.append("[Unknown Data Type ").append(header).append("]");
}
return bf.toString();
}
public static String extractFormParam(HttpPostRequestDecoder decoder, String name, boolean required) throws IOException {
InterfaceHttpData data = decoder.getBodyHttpData(name);
if(data != null && data.getHttpDataType() == HttpDataType.Attribute) {
Attribute attribute = (Attribute) data;
return attribute.getValue();
}
if(required) {
throw new MissingParameterException(name);
}
return null;
}
/**
* Get POST Parma
* Map
*
* @return
*/
public Map<String, String> getPostParm() throws UnsupportedEncodingException {
Map<String, String> map = new HashMap<>();
try {
List<InterfaceHttpData> parmList = decoder.getBodyHttpDatas();
for (InterfaceHttpData parm : parmList) {
MixedAttribute data = (MixedAttribute) parm;
data.setCharset(Charset.forName("UTF-8"));
map.put(data.getName(), data.getValue());
}
} catch (IOException e) {
e.printStackTrace();
}
return map;
}
private void doPost(ChannelHandlerContext ctx, SessionContext sctx) {
WebRequest webRequest = getWebRequest();
JSONObject data = webRequest.getData();
try {
while (postRequestDecoder.hasNext()) {
InterfaceHttpData httpData = postRequestDecoder.next();
try {
if (httpData.getHttpDataType() == HttpDataType.Attribute ||
httpData.getHttpDataType() == HttpDataType.InternalAttribute) {
Attribute attribute = (Attribute) httpData;
data.put(attribute.getName(), attribute.getValue());
} else if (httpData.getHttpDataType() == HttpDataType.FileUpload) {
FileUpload fileUpload = (FileUpload) httpData;
if (fileUpload.isCompleted()) {
webRequest.getFileUploadMap().put(fileUpload.getName(), new WebFileUpload(fileUpload));
} else {
log.error("fileUpload not complete name[{}]", fileUpload.getName());
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
} finally {
postRequestDecoder.removeHttpDataFromClean(httpData);
httpData.release();
}
}
} catch (EndOfDataDecoderException ignored) {
}
if (webRequest.isDynamic()) {
doWork(ctx, sctx, webRequest);
} else {
doFile(ctx, sctx, webRequest);
}
}
/**
* This getMethod returns a List of all HttpDatas from body.<br>
*
* If chunked, all chunks must have been offered using offer() getMethod. If
* not, NotEnoughDataDecoderException will be raised.
*
* @return the list of HttpDatas from Body part for POST getMethod
* @throws NotEnoughDataDecoderException Need more chunks
*/
@Override
public List<InterfaceHttpData> getBodyHttpDatas() {
checkDestroyed();
if (!isLastChunk) {
throw new NotEnoughDataDecoderException();
}
return bodyListHttpData;
}
/**
* This getMethod returns the first InterfaceHttpData with the given name from
* body.<br>
*
* If chunked, all chunks must have been offered using offer() getMethod. If
* not, NotEnoughDataDecoderException will be raised.
*
* @return The first Body InterfaceHttpData with the given name (ignore case)
* @throws NotEnoughDataDecoderException need more chunks
*/
@Override
public InterfaceHttpData getBodyHttpData(String name) {
checkDestroyed();
if (!isLastChunk) {
throw new NotEnoughDataDecoderException();
}
List<InterfaceHttpData> list = bodyMapHttpData.get(name);
if (list != null) {
return list.get(0);
}
return null;
}
@Override
public InterfaceHttpData currentPartialHttpData() {
if (currentFileUpload != null) {
return currentFileUpload;
} else {
return currentAttribute;
}
}
/**
* Utility function to add a new decoded data
*/
protected void addHttpData(InterfaceHttpData data) {
if (data == null) {
return;
}
List<InterfaceHttpData> datas = bodyMapHttpData.get(data.getName());
if (datas == null) {
datas = new ArrayList<InterfaceHttpData>(1);
bodyMapHttpData.put(data.getName(), datas);
}
datas.add(data);
bodyListHttpData.add(data);
}
/**
* Parse the Body for multipart
*
* @throws ErrorDataDecoderException if there is a problem with the charset
* decoding or other errors
*/
private void parseBodyMultipart() {
if (undecodedChunk == null || undecodedChunk.readableBytes() == 0) {
// nothing to decode
return;
}
InterfaceHttpData data = decodeMultipart(currentStatus);
while (data != null) {
addHttpData(data);
if (currentStatus == MultiPartStatus.PREEPILOGUE || currentStatus == MultiPartStatus.EPILOGUE) {
break;
}
data = decodeMultipart(currentStatus);
}
}
/**
* Remove the given FileUpload from the list of FileUploads to clean
*/
@Override
public void removeHttpDataFromClean(InterfaceHttpData data) {
checkDestroyed();
factory.removeHttpDataFromClean(request, data);
}
private void parseParameter() {
this.parameterParsed = true;
//解析query参数,默认使用UTF8编码
QueryStringDecoder queryDecoder = new QueryStringDecoder(this.uri);
queryDecoder.parameters().forEach((k, v) -> {
if (v != null && v.size() > 0) {
parameters.put(k, v.get(0));
}
});
if (this.method == HttpMethod.GET) {
return;
}
//解析post参数
HttpPostRequestDecoder postDecoder = new HttpPostRequestDecoder(this.msg);
postDecoder.getBodyHttpDatas().forEach(v -> {
if (v.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
Attribute attribute = (Attribute) v;
try {
this.parameters.put(attribute.getName(), attribute.getValue());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
@Override
public @NotNull CompletableFuture<ResponseInfo<String>> execute(
@NotNull RequestInfo<String> request,
@NotNull Executor longRunningTaskExecutor,
@NotNull ChannelHandlerContext ctx
) {
List<String> hashesFound = new ArrayList<>();
for (InterfaceHttpData multipartData : request.getMultipartParts()) {
String name = multipartData.getName();
byte[] payloadBytes;
try {
payloadBytes = ((HttpData)multipartData).get();
} catch (IOException e) {
throw new RuntimeException(e);
}
String filename = null;
switch (multipartData.getHttpDataType()) {
case Attribute:
// Do nothing - filename stays null
break;
case FileUpload:
filename = ((FileUpload)multipartData).getFilename();
break;
default:
throw new RuntimeException("Unsupported multipart type: " + multipartData.getHttpDataType().name());
}
hashesFound.add(getHashForMultipartPayload(name, filename, payloadBytes));
}
return CompletableFuture.completedFuture(ResponseInfo.newBuilder(StringUtils.join(hashesFound, ",")).build());
}
/**
* {@inheritDoc}
*/
@Override
public synchronized @Nullable List<InterfaceHttpData> getMultipartParts() {
if (!isMultipartRequest() || !isCompleteRequestWithAllChunks())
return null;
if (multipartData == null) {
byte[] contentBytes = getRawContentBytes();
HttpVersion httpVersion = getProtocolVersion();
HttpMethod httpMethod = getMethod();
// HttpVersion and HttpMethod cannot be null because DefaultFullHttpRequest doesn't allow them to be
// null, but our getProtocolVersion() and getMethod() methods might return null (i.e. due to an
// invalid request). They shouldn't be null in practice by the time this getMultipartParts() method
// is called, but since they don't seem to be used by the Netty code we delegate to, we can just
// default them to something if null somehow slips through.
if (httpVersion == null) {
httpVersion = HttpVersion.HTTP_1_0;
}
if (httpMethod == null) {
httpMethod = HttpMethod.POST;
}
HttpRequest fullHttpRequestForMultipartDecoder =
(contentBytes == null)
? new DefaultFullHttpRequest(httpVersion, httpMethod, getUri())
: new DefaultFullHttpRequest(httpVersion, httpMethod, getUri(),
Unpooled.wrappedBuffer(contentBytes));
fullHttpRequestForMultipartDecoder.headers().add(getHeaders());
multipartData = new HttpPostMultipartRequestDecoder(
new DefaultHttpDataFactory(false), fullHttpRequestForMultipartDecoder, getContentCharset()
);
}
return multipartData.getBodyHttpDatas();
}