ex
Fork of mbed-os-example-mbed5-blinky by
dcs-sdk-java-master/app/src/main/java/com/baidu/duer/dcs/framework/dispatcher/MultipartParser.java@45:2aa9f933c8d2, 2017-07-18 (annotated)
- Committer:
- TMBOY
- Date:
- Tue Jul 18 16:34:48 2017 +0800
- Revision:
- 45:2aa9f933c8d2
?
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| TMBOY | 45:2aa9f933c8d2 | 1 | /* |
| TMBOY | 45:2aa9f933c8d2 | 2 | * Copyright (c) 2017 Baidu, Inc. All Rights Reserved. |
| TMBOY | 45:2aa9f933c8d2 | 3 | * |
| TMBOY | 45:2aa9f933c8d2 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| TMBOY | 45:2aa9f933c8d2 | 5 | * you may not use this file except in compliance with the License. |
| TMBOY | 45:2aa9f933c8d2 | 6 | * You may obtain a copy of the License at |
| TMBOY | 45:2aa9f933c8d2 | 7 | * |
| TMBOY | 45:2aa9f933c8d2 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| TMBOY | 45:2aa9f933c8d2 | 9 | * |
| TMBOY | 45:2aa9f933c8d2 | 10 | * Unless required by applicable law or agreed to in writing, software |
| TMBOY | 45:2aa9f933c8d2 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| TMBOY | 45:2aa9f933c8d2 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| TMBOY | 45:2aa9f933c8d2 | 13 | * See the License for the specific language governing permissions and |
| TMBOY | 45:2aa9f933c8d2 | 14 | * limitations under the License. |
| TMBOY | 45:2aa9f933c8d2 | 15 | */ |
| TMBOY | 45:2aa9f933c8d2 | 16 | package com.baidu.duer.dcs.framework.dispatcher; |
| TMBOY | 45:2aa9f933c8d2 | 17 | |
| TMBOY | 45:2aa9f933c8d2 | 18 | import com.baidu.duer.dcs.framework.message.DcsResponseBody; |
| TMBOY | 45:2aa9f933c8d2 | 19 | import com.baidu.duer.dcs.http.HttpConfig; |
| TMBOY | 45:2aa9f933c8d2 | 20 | |
| TMBOY | 45:2aa9f933c8d2 | 21 | import org.apache.commons.fileupload.MultipartStream; |
| TMBOY | 45:2aa9f933c8d2 | 22 | import org.apache.commons.lang3.StringUtils; |
| TMBOY | 45:2aa9f933c8d2 | 23 | |
| TMBOY | 45:2aa9f933c8d2 | 24 | import java.io.BufferedReader; |
| TMBOY | 45:2aa9f933c8d2 | 25 | import java.io.ByteArrayOutputStream; |
| TMBOY | 45:2aa9f933c8d2 | 26 | import java.io.IOException; |
| TMBOY | 45:2aa9f933c8d2 | 27 | import java.io.InputStream; |
| TMBOY | 45:2aa9f933c8d2 | 28 | import java.io.StringReader; |
| TMBOY | 45:2aa9f933c8d2 | 29 | import java.util.HashMap; |
| TMBOY | 45:2aa9f933c8d2 | 30 | import java.util.Map; |
| TMBOY | 45:2aa9f933c8d2 | 31 | |
| TMBOY | 45:2aa9f933c8d2 | 32 | import okhttp3.Response; |
| TMBOY | 45:2aa9f933c8d2 | 33 | |
| TMBOY | 45:2aa9f933c8d2 | 34 | /** |
| TMBOY | 45:2aa9f933c8d2 | 35 | * 把从服务器返回multipart中json对象和二进制解析成directive对象 |
| TMBOY | 45:2aa9f933c8d2 | 36 | * <p> |
| TMBOY | 45:2aa9f933c8d2 | 37 | * Created by wuruisheng on 2017/5/12. |
| TMBOY | 45:2aa9f933c8d2 | 38 | */ |
| TMBOY | 45:2aa9f933c8d2 | 39 | public class MultipartParser extends Parser { |
| TMBOY | 45:2aa9f933c8d2 | 40 | private static final int BUFFER_SIZE = 512; |
| TMBOY | 45:2aa9f933c8d2 | 41 | private final IMultipartParserListener multipartParserListener; |
| TMBOY | 45:2aa9f933c8d2 | 42 | |
| TMBOY | 45:2aa9f933c8d2 | 43 | public MultipartParser(IMultipartParserListener listener) { |
| TMBOY | 45:2aa9f933c8d2 | 44 | this.multipartParserListener = listener; |
| TMBOY | 45:2aa9f933c8d2 | 45 | } |
| TMBOY | 45:2aa9f933c8d2 | 46 | |
| TMBOY | 45:2aa9f933c8d2 | 47 | public void parseResponse(Response response) throws IOException { |
| TMBOY | 45:2aa9f933c8d2 | 48 | String boundary = getBoundary(response); |
| TMBOY | 45:2aa9f933c8d2 | 49 | if (boundary != null) { |
| TMBOY | 45:2aa9f933c8d2 | 50 | parseStream(response.body().byteStream(), boundary); |
| TMBOY | 45:2aa9f933c8d2 | 51 | } |
| TMBOY | 45:2aa9f933c8d2 | 52 | } |
| TMBOY | 45:2aa9f933c8d2 | 53 | |
| TMBOY | 45:2aa9f933c8d2 | 54 | private void parseStream(InputStream inputStream, String boundary) throws IOException { |
| TMBOY | 45:2aa9f933c8d2 | 55 | MultipartStream multipartStream = new MultipartStream(inputStream, boundary.getBytes(), BUFFER_SIZE, null); |
| TMBOY | 45:2aa9f933c8d2 | 56 | parseMultipartStream(multipartStream); |
| TMBOY | 45:2aa9f933c8d2 | 57 | } |
| TMBOY | 45:2aa9f933c8d2 | 58 | |
| TMBOY | 45:2aa9f933c8d2 | 59 | private void parseMultipartStream(MultipartStream multipartStream) throws IOException { |
| TMBOY | 45:2aa9f933c8d2 | 60 | try { |
| TMBOY | 45:2aa9f933c8d2 | 61 | Boolean hasNextPart = multipartStream.skipPreamble(); |
| TMBOY | 45:2aa9f933c8d2 | 62 | while (hasNextPart) { |
| TMBOY | 45:2aa9f933c8d2 | 63 | handlePart(multipartStream); |
| TMBOY | 45:2aa9f933c8d2 | 64 | hasNextPart = multipartStream.readBoundary(); |
| TMBOY | 45:2aa9f933c8d2 | 65 | } |
| TMBOY | 45:2aa9f933c8d2 | 66 | } catch (DcsJsonProcessingException exception) { |
| TMBOY | 45:2aa9f933c8d2 | 67 | if (multipartParserListener != null) { |
| TMBOY | 45:2aa9f933c8d2 | 68 | multipartParserListener.onParseFailed(exception.getUnparsedCotent()); |
| TMBOY | 45:2aa9f933c8d2 | 69 | } |
| TMBOY | 45:2aa9f933c8d2 | 70 | } catch (MultipartStream.MalformedStreamException exception) { |
| TMBOY | 45:2aa9f933c8d2 | 71 | // 用于处理 empty part |
| TMBOY | 45:2aa9f933c8d2 | 72 | } |
| TMBOY | 45:2aa9f933c8d2 | 73 | } |
| TMBOY | 45:2aa9f933c8d2 | 74 | |
| TMBOY | 45:2aa9f933c8d2 | 75 | private void handlePart(MultipartStream multipartStream) throws IOException { |
| TMBOY | 45:2aa9f933c8d2 | 76 | Map<String, String> headers = getPartHeaders(multipartStream); |
| TMBOY | 45:2aa9f933c8d2 | 77 | if (headers != null) { |
| TMBOY | 45:2aa9f933c8d2 | 78 | byte[] partBytes = getPartBytes(multipartStream); |
| TMBOY | 45:2aa9f933c8d2 | 79 | Boolean isJsonData = isPartJSON(headers); |
| TMBOY | 45:2aa9f933c8d2 | 80 | if (isJsonData) { |
| TMBOY | 45:2aa9f933c8d2 | 81 | handleJsonData(partBytes); |
| TMBOY | 45:2aa9f933c8d2 | 82 | } else { |
| TMBOY | 45:2aa9f933c8d2 | 83 | handleAudio(headers, partBytes); |
| TMBOY | 45:2aa9f933c8d2 | 84 | } |
| TMBOY | 45:2aa9f933c8d2 | 85 | } |
| TMBOY | 45:2aa9f933c8d2 | 86 | } |
| TMBOY | 45:2aa9f933c8d2 | 87 | |
| TMBOY | 45:2aa9f933c8d2 | 88 | private void handleJsonData(byte[] partBytes) throws IOException { |
| TMBOY | 45:2aa9f933c8d2 | 89 | final DcsResponseBody responseBody = parse(partBytes, DcsResponseBody.class); |
| TMBOY | 45:2aa9f933c8d2 | 90 | if (multipartParserListener != null) { |
| TMBOY | 45:2aa9f933c8d2 | 91 | multipartParserListener.onResponseBody(responseBody); |
| TMBOY | 45:2aa9f933c8d2 | 92 | } |
| TMBOY | 45:2aa9f933c8d2 | 93 | } |
| TMBOY | 45:2aa9f933c8d2 | 94 | |
| TMBOY | 45:2aa9f933c8d2 | 95 | private void handleAudio(Map<String, String> headers, byte[] partBytes) { |
| TMBOY | 45:2aa9f933c8d2 | 96 | String contentId = getMultipartContentId(headers); |
| TMBOY | 45:2aa9f933c8d2 | 97 | final AudioData audioData = new AudioData(contentId, partBytes); |
| TMBOY | 45:2aa9f933c8d2 | 98 | if (multipartParserListener != null) { |
| TMBOY | 45:2aa9f933c8d2 | 99 | multipartParserListener.onAudioData(audioData); |
| TMBOY | 45:2aa9f933c8d2 | 100 | } |
| TMBOY | 45:2aa9f933c8d2 | 101 | } |
| TMBOY | 45:2aa9f933c8d2 | 102 | |
| TMBOY | 45:2aa9f933c8d2 | 103 | private byte[] getPartBytes(MultipartStream multipartStream) throws IOException { |
| TMBOY | 45:2aa9f933c8d2 | 104 | ByteArrayOutputStream data = new ByteArrayOutputStream(); |
| TMBOY | 45:2aa9f933c8d2 | 105 | multipartStream.readBodyData(data); |
| TMBOY | 45:2aa9f933c8d2 | 106 | return data.toByteArray(); |
| TMBOY | 45:2aa9f933c8d2 | 107 | } |
| TMBOY | 45:2aa9f933c8d2 | 108 | |
| TMBOY | 45:2aa9f933c8d2 | 109 | private Map<String, String> getPartHeaders(MultipartStream multipartStream) throws IOException { |
| TMBOY | 45:2aa9f933c8d2 | 110 | String headers = multipartStream.readHeaders(); |
| TMBOY | 45:2aa9f933c8d2 | 111 | BufferedReader reader = new BufferedReader(new StringReader(headers)); |
| TMBOY | 45:2aa9f933c8d2 | 112 | Map<String, String> headerMap = new HashMap<>(); |
| TMBOY | 45:2aa9f933c8d2 | 113 | try { |
| TMBOY | 45:2aa9f933c8d2 | 114 | for (String line = reader.readLine(); line != null; line = reader.readLine()) { |
| TMBOY | 45:2aa9f933c8d2 | 115 | line = line.trim(); |
| TMBOY | 45:2aa9f933c8d2 | 116 | if (!StringUtils.isBlank(line) && line.contains(":")) { |
| TMBOY | 45:2aa9f933c8d2 | 117 | int colon = line.indexOf(":"); |
| TMBOY | 45:2aa9f933c8d2 | 118 | String headerName = line.substring(0, colon).trim(); |
| TMBOY | 45:2aa9f933c8d2 | 119 | String headerValue = line.substring(colon + 1).trim(); |
| TMBOY | 45:2aa9f933c8d2 | 120 | headerMap.put(headerName.toLowerCase(), headerValue); |
| TMBOY | 45:2aa9f933c8d2 | 121 | } |
| TMBOY | 45:2aa9f933c8d2 | 122 | } |
| TMBOY | 45:2aa9f933c8d2 | 123 | } catch (Exception e) { |
| TMBOY | 45:2aa9f933c8d2 | 124 | throw e; |
| TMBOY | 45:2aa9f933c8d2 | 125 | } |
| TMBOY | 45:2aa9f933c8d2 | 126 | |
| TMBOY | 45:2aa9f933c8d2 | 127 | return headerMap; |
| TMBOY | 45:2aa9f933c8d2 | 128 | } |
| TMBOY | 45:2aa9f933c8d2 | 129 | |
| TMBOY | 45:2aa9f933c8d2 | 130 | private String getMultipartHeaderValue(Map<String, String> headers, String searchHeader) { |
| TMBOY | 45:2aa9f933c8d2 | 131 | return headers.get(searchHeader.toLowerCase()); |
| TMBOY | 45:2aa9f933c8d2 | 132 | } |
| TMBOY | 45:2aa9f933c8d2 | 133 | |
| TMBOY | 45:2aa9f933c8d2 | 134 | private String getMultipartContentId(Map<String, String> headers) { |
| TMBOY | 45:2aa9f933c8d2 | 135 | String contentId = getMultipartHeaderValue(headers, HttpConfig.HttpHeaders.CONTENT_ID); |
| TMBOY | 45:2aa9f933c8d2 | 136 | contentId = contentId.substring(1, contentId.length() - 1); |
| TMBOY | 45:2aa9f933c8d2 | 137 | return contentId; |
| TMBOY | 45:2aa9f933c8d2 | 138 | } |
| TMBOY | 45:2aa9f933c8d2 | 139 | |
| TMBOY | 45:2aa9f933c8d2 | 140 | private boolean isPartJSON(Map<String, String> headers) { |
| TMBOY | 45:2aa9f933c8d2 | 141 | String contentType = getMultipartHeaderValue(headers, HttpConfig.HttpHeaders.CONTENT_TYPE); |
| TMBOY | 45:2aa9f933c8d2 | 142 | return StringUtils.contains(contentType, HttpConfig.ContentTypes.JSON); |
| TMBOY | 45:2aa9f933c8d2 | 143 | } |
| TMBOY | 45:2aa9f933c8d2 | 144 | |
| TMBOY | 45:2aa9f933c8d2 | 145 | private static String getBoundary(Response response) { |
| TMBOY | 45:2aa9f933c8d2 | 146 | String headerValue = response.header(HttpConfig.HttpHeaders.CONTENT_TYPE); |
| TMBOY | 45:2aa9f933c8d2 | 147 | String boundary = getHeaderParameter(headerValue, HttpConfig.Parameters.BOUNDARY); |
| TMBOY | 45:2aa9f933c8d2 | 148 | return boundary; |
| TMBOY | 45:2aa9f933c8d2 | 149 | } |
| TMBOY | 45:2aa9f933c8d2 | 150 | |
| TMBOY | 45:2aa9f933c8d2 | 151 | private static String getHeaderParameter(final String headerValue, final String key) { |
| TMBOY | 45:2aa9f933c8d2 | 152 | if ((headerValue == null) || (key == null)) { |
| TMBOY | 45:2aa9f933c8d2 | 153 | return null; |
| TMBOY | 45:2aa9f933c8d2 | 154 | } |
| TMBOY | 45:2aa9f933c8d2 | 155 | |
| TMBOY | 45:2aa9f933c8d2 | 156 | String[] parts = headerValue.split(";"); |
| TMBOY | 45:2aa9f933c8d2 | 157 | for (String part : parts) { |
| TMBOY | 45:2aa9f933c8d2 | 158 | part = part.trim(); |
| TMBOY | 45:2aa9f933c8d2 | 159 | if (part.startsWith(key)) { |
| TMBOY | 45:2aa9f933c8d2 | 160 | return part.substring(key.length() + 1).replaceAll("(^\")|(\"$)", "").trim(); |
| TMBOY | 45:2aa9f933c8d2 | 161 | } |
| TMBOY | 45:2aa9f933c8d2 | 162 | } |
| TMBOY | 45:2aa9f933c8d2 | 163 | |
| TMBOY | 45:2aa9f933c8d2 | 164 | return null; |
| TMBOY | 45:2aa9f933c8d2 | 165 | } |
| TMBOY | 45:2aa9f933c8d2 | 166 | |
| TMBOY | 45:2aa9f933c8d2 | 167 | public interface IMultipartParserListener { |
| TMBOY | 45:2aa9f933c8d2 | 168 | void onResponseBody(DcsResponseBody responseBody); |
| TMBOY | 45:2aa9f933c8d2 | 169 | |
| TMBOY | 45:2aa9f933c8d2 | 170 | void onAudioData(AudioData audioData); |
| TMBOY | 45:2aa9f933c8d2 | 171 | |
| TMBOY | 45:2aa9f933c8d2 | 172 | void onParseFailed(String unParseMessage); |
| TMBOY | 45:2aa9f933c8d2 | 173 | } |
| TMBOY | 45:2aa9f933c8d2 | 174 | } |
