/server/src/main/java/com/orientechnologies/orient/server/network/protocol/http/multipart/OHttpMultipartRequestCommand.java

https://github.com/cloudsmith/orientdb · Java · 257 lines · 217 code · 20 blank · 20 comment · 54 complexity · b5c6d4620b18bc8d0b404a6214cb2ffc MD5 · raw file

  1. /*
  2. *
  3. * Copyright 2011 Luca Molino (luca.molino--AT--assetdata.it)
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package com.orientechnologies.orient.server.network.protocol.http.multipart;
  18. import java.io.IOException;
  19. import java.util.HashMap;
  20. import java.util.LinkedHashMap;
  21. import com.orientechnologies.orient.core.db.record.ODatabaseRecord;
  22. import com.orientechnologies.orient.server.network.protocol.http.OHttpRequest;
  23. import com.orientechnologies.orient.server.network.protocol.http.OHttpUtils;
  24. import com.orientechnologies.orient.server.network.protocol.http.command.OServerCommandAuthenticatedDbAbstract;
  25. /**
  26. * @author luca.molino
  27. *
  28. */
  29. public abstract class OHttpMultipartRequestCommand<B, F> extends OServerCommandAuthenticatedDbAbstract {
  30. private STATUS parseStatus = STATUS.STATUS_EXPECTED_BOUNDARY;
  31. protected static enum STATUS {
  32. STATUS_EXPECTED_BOUNDARY, STATUS_EXPECTED_BOUNDARY_CRLF, STATUS_EXPECTED_PART_HEADERS, STATUS_EXPECTED_PART_CONTENT, STATUS_EXPECTED_END_REQUEST
  33. }
  34. public void parse(OHttpRequest iRequest, OHttpMultipartContentParser<B> standardContentParser,
  35. OHttpMultipartContentParser<F> fileContentParser, ODatabaseRecord database) throws IOException {
  36. int in;
  37. char currChar;
  38. boolean endRequest = false;
  39. OHttpMultipartContentInputStream contentIn = new OHttpMultipartContentInputStream(iRequest.multipartStream, iRequest.boundary);
  40. HashMap<String, String> headers = new LinkedHashMap<String, String>();
  41. try {
  42. while (iRequest.multipartStream.available() > 0 && !endRequest) {
  43. in = iRequest.multipartStream.read();
  44. currChar = (char) in;
  45. switch (parseStatus) {
  46. case STATUS_EXPECTED_BOUNDARY: {
  47. readBoundary(iRequest, currChar);
  48. parseStatus = STATUS.STATUS_EXPECTED_BOUNDARY_CRLF;
  49. break;
  50. }
  51. case STATUS_EXPECTED_BOUNDARY_CRLF: {
  52. endRequest = readBoundaryCrLf(iRequest, currChar, endRequest);
  53. parseStatus = STATUS.STATUS_EXPECTED_PART_HEADERS;
  54. break;
  55. }
  56. case STATUS_EXPECTED_PART_HEADERS: {
  57. parsePartHeaders(iRequest, currChar, endRequest, headers);
  58. parseStatus = STATUS.STATUS_EXPECTED_PART_CONTENT;
  59. break;
  60. }
  61. case STATUS_EXPECTED_PART_CONTENT: {
  62. iRequest.multipartStream.setSkipInput(in);
  63. contentIn.reset();
  64. if (headers.get(OHttpUtils.MULTIPART_CONTENT_FILENAME) != null) {
  65. parseFileContent(iRequest, fileContentParser, headers, contentIn, database);
  66. } else {
  67. parseBaseContent(iRequest, standardContentParser, headers, contentIn, database);
  68. }
  69. break;
  70. }
  71. case STATUS_EXPECTED_END_REQUEST: {
  72. iRequest.multipartStream.setSkipInput(in);
  73. endRequest = OHttpMultipartHelper.isEndRequest(iRequest);
  74. if (!endRequest) {
  75. parseStatus = STATUS.STATUS_EXPECTED_BOUNDARY_CRLF;
  76. } else {
  77. parseStatus = STATUS.STATUS_EXPECTED_BOUNDARY;
  78. }
  79. break;
  80. }
  81. }
  82. }
  83. parseStatus = STATUS.STATUS_EXPECTED_BOUNDARY;
  84. } catch (Exception e) {
  85. sendTextContent(iRequest, OHttpUtils.STATUS_INTERNALERROR, e.getMessage(), null, OHttpUtils.CONTENT_TEXT_PLAIN,
  86. e.getMessage());
  87. }
  88. }
  89. protected boolean readBoundaryCrLf(final OHttpRequest iRequest, char currChar, boolean endRequest) throws IOException {
  90. int in;
  91. if (currChar == '\r') {
  92. in = iRequest.multipartStream.read();
  93. currChar = (char) in;
  94. if (currChar == '\n') {
  95. return false;
  96. }
  97. } else if (currChar == '-') {
  98. in = iRequest.multipartStream.read();
  99. currChar = (char) in;
  100. if (currChar == '-') {
  101. endRequest = true;
  102. } else {
  103. sendTextContent(iRequest, OHttpUtils.STATUS_INVALIDMETHOD_CODE, "Wrong request: Expected -", null,
  104. OHttpUtils.CONTENT_TEXT_PLAIN, "Wrong request: Expected -");
  105. endRequest = true;
  106. }
  107. } else {
  108. sendTextContent(iRequest, OHttpUtils.STATUS_INVALIDMETHOD_CODE, "Wrong request: Expected CR/LF", null,
  109. OHttpUtils.CONTENT_TEXT_PLAIN, "Wrong request: Expected CR/LF");
  110. endRequest = true;
  111. }
  112. return endRequest;
  113. }
  114. protected void readBoundary(final OHttpRequest iRequest, char currChar) throws IOException {
  115. int in;
  116. int boundaryCursor = 0;
  117. for (int i = 0; i < 2; i++) {
  118. if (currChar != '-') {
  119. sendTextContent(iRequest, OHttpUtils.STATUS_INVALIDMETHOD_CODE, "Wrong request: Expected boundary", null,
  120. OHttpUtils.CONTENT_TEXT_PLAIN, "Wrong request: Expected boundary");
  121. return;
  122. }
  123. in = iRequest.multipartStream.read();
  124. currChar = (char) in;
  125. }
  126. while (boundaryCursor < iRequest.boundary.length()) {
  127. if (currChar != iRequest.boundary.charAt(boundaryCursor)) {
  128. sendTextContent(iRequest, OHttpUtils.STATUS_INVALIDMETHOD_CODE, "Wrong request: Expected boundary", null,
  129. OHttpUtils.CONTENT_TEXT_PLAIN, "Wrong request: Expected boundary");
  130. }
  131. boundaryCursor++;
  132. if (boundaryCursor < iRequest.boundary.length()) {
  133. in = iRequest.multipartStream.read();
  134. currChar = (char) in;
  135. }
  136. }
  137. }
  138. protected void parsePartHeaders(final OHttpRequest iRequest, char currChar, boolean endRequest,
  139. final HashMap<String, String> headers) throws IOException {
  140. int in;
  141. StringBuilder headerName = new StringBuilder();
  142. boolean endOfHeaders = false;
  143. while (!endOfHeaders) {
  144. headerName.append(currChar);
  145. if (OHttpMultipartHelper.isMultipartPartHeader(headerName)) {
  146. currChar = parseHeader(iRequest, headers, headerName.toString());
  147. headerName.setLength(0);
  148. }
  149. if (currChar == '\r') {
  150. in = iRequest.multipartStream.read();
  151. currChar = (char) in;
  152. if (currChar == '\n') {
  153. in = iRequest.multipartStream.read();
  154. currChar = (char) in;
  155. if (currChar == '\r') {
  156. in = iRequest.multipartStream.read();
  157. currChar = (char) in;
  158. if (currChar == '\n') {
  159. endOfHeaders = true;
  160. }
  161. }
  162. }
  163. } else {
  164. in = iRequest.multipartStream.read();
  165. currChar = (char) in;
  166. }
  167. }
  168. }
  169. protected char parseHeader(final OHttpRequest iRequest, HashMap<String, String> headers, final String headerName)
  170. throws IOException {
  171. final StringBuilder header = new StringBuilder();
  172. boolean endOfHeader = false;
  173. int in;
  174. char currChar;
  175. in = iRequest.multipartStream.read();
  176. currChar = (char) in;
  177. if (currChar == ':') {
  178. in = iRequest.multipartStream.read();
  179. currChar = (char) in;
  180. if (currChar != ' ') {
  181. sendTextContent(iRequest, OHttpUtils.STATUS_INVALIDMETHOD_CODE, "Wrong request part header: Expected ' ' (header: "
  182. + headerName + ")", null, OHttpUtils.CONTENT_TEXT_PLAIN, "Wrong request part header: Expected ' ' (header: "
  183. + headerName + ")");
  184. }
  185. } else if (currChar != '=') {
  186. sendTextContent(iRequest, OHttpUtils.STATUS_INVALIDMETHOD_CODE, "Wrong request part header: Expected ':' (header: "
  187. + headerName + ")", null, OHttpUtils.CONTENT_TEXT_PLAIN, "Wrong request part header: Expected ':' (header: " + headerName
  188. + ")");
  189. }
  190. while (!endOfHeader) {
  191. in = iRequest.multipartStream.read();
  192. currChar = (char) in;
  193. if (currChar == ';') {
  194. if (header.charAt(0) == '"') {
  195. header.deleteCharAt(0);
  196. }
  197. if (header.charAt(header.length() - 1) == '"') {
  198. header.deleteCharAt(header.length() - 1);
  199. }
  200. headers.put(headerName, header.toString());
  201. in = iRequest.multipartStream.read();
  202. return (char) in;
  203. } else if (currChar == '\r') {
  204. if (header.charAt(0) == '"') {
  205. header.deleteCharAt(0);
  206. }
  207. if (header.charAt(header.length() - 1) == '"') {
  208. header.deleteCharAt(header.length() - 1);
  209. }
  210. headers.put(headerName, header.toString());
  211. return currChar;
  212. }
  213. header.append(currChar);
  214. }
  215. return currChar;
  216. }
  217. protected void parseBaseContent(final OHttpRequest iRequest, final OHttpMultipartContentParser<B> contentParser,
  218. final HashMap<String, String> headers, final OHttpMultipartContentInputStream in, ODatabaseRecord database) throws Exception {
  219. B result = contentParser.parse(iRequest, headers, in, database);
  220. parseStatus = STATUS.STATUS_EXPECTED_END_REQUEST;
  221. processBaseContent(iRequest, result, headers);
  222. headers.clear();
  223. }
  224. protected void parseFileContent(final OHttpRequest iRequest, final OHttpMultipartContentParser<F> contentParser,
  225. final HashMap<String, String> headers, final OHttpMultipartContentInputStream in, ODatabaseRecord database) throws Exception {
  226. F result = contentParser.parse(iRequest, headers, in, database);
  227. parseStatus = STATUS.STATUS_EXPECTED_END_REQUEST;
  228. processFileContent(iRequest, result, headers);
  229. headers.clear();
  230. }
  231. protected abstract void processBaseContent(final OHttpRequest iRequest, B iContentResult, HashMap<String, String> headers)
  232. throws Exception;
  233. protected abstract void processFileContent(final OHttpRequest iRequest, F iContentResult, HashMap<String, String> headers)
  234. throws Exception;
  235. protected abstract String getFileParamenterName();
  236. protected abstract String getDocumentParamenterName();
  237. }