All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.basho.riak.client.util.Multipart Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/*
 * This file is provided to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.basho.riak.client.util;

import static com.basho.riak.client.util.CharsetUtils.asString;
import static com.basho.riak.client.util.CharsetUtils.getCharset;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

import org.apache.http.util.EncodingUtils;

/**
 * Represents a multipart entity as described here:
 * 
 * http://tools.ietf.org/html/rfc2046#section-5.1
 *
 * @deprecated with the addition of a protocol buffers client in 0.14 all the
 *             existing REST client code should be in client.http.* this class
 *             has therefore been moved. Please use
 *             com.basho.riak.client.http.util.Multipart
 *             instead.
 *             

WARNING: This class will be REMOVED in the next version.

* @see com.basho.riak.client.http.util.Multipart */ @Deprecated public class Multipart { private static byte[] HEADER_DELIM = CharsetUtils.utf8StringToBytes("\r\n\r\n"); private static int indexOf(byte[] text, byte[] pattern, int fromIndex) { if (fromIndex >= text.length || fromIndex < 0) { throw new IllegalArgumentException("index not within range"); } if (pattern.length == 0) { throw new IllegalArgumentException("pattern must not be empty"); } byte first = pattern[0]; int max = text.length - pattern.length; for (int i = fromIndex; i <= max; i++) { if (text[i] != first) { while (i <= max && text[i] != first) { i++; } } if (i <= max) { int j = i + 1; int end = j + pattern.length - 1; for (int k = 1; j < end && text[j] == pattern[k]; j++, k++); if (j == end) { return i; } } } return -1; } /** * Parses a multipart message or a multipart subpart of a multipart message. * * @return A list of the parts parsed into headers and body of this * multipart message */ public static List parse(Map headers, byte[] body) { if (headers == null || body == null || body.length == 0) return null; if (!(body.length >= 2 && body[0] == '\r' && body[1] == '\n')) { // In order to parse the multipart efficiently, we want to treat the // first boundary identically to the others, so make sure that the // first boundary is preceded by a '\r\n' like the others byte[] newBody = new byte[body.length + 2]; newBody[0] = '\r'; newBody[1] = '\n'; System.arraycopy(body, 0, newBody, 2, body.length); body = newBody; } String boundary = "\r\n--" + getBoundary(headers.get(Constants.HDR_CONTENT_TYPE)); byte[] boundaryBytes = CharsetUtils.utf8StringToBytes(boundary); int boundarySize = boundary.length(); if ("\r\n--".equals(boundary)) return null; // While this parsing could be more efficiently done in one pass with a // hand written FSM, hopefully this method is more readable/intuitive. List parts = new ArrayList(); int pos = indexOf(body, boundaryBytes, 0); if (pos != -1) { while (pos < body.length) { // first char of part int start = pos + boundarySize; // last char of part + 1 int end = indexOf(body, boundaryBytes, start); // end of header section + 1 int headerEnd = indexOf(body, HEADER_DELIM, pos); // start of body section int bodyStart = headerEnd + HEADER_DELIM.length; // check for end boundary, which is (boundary + "--") if (body.length >= (start + 2) && body[start] == '-' && body[start+1] == '-') { break; } if (end == -1) { end = body.length; } if (headerEnd == -1) { headerEnd = body.length; bodyStart = end; } if (bodyStart > end) { bodyStart = end; } Map partHeaders = parseHeaders(EncodingUtils.getAsciiString(copyOfRange(body, start, headerEnd))); parts.add(new Part(partHeaders, copyOfRange(body, bodyStart, end))); pos = end; } } return parts; } /** * A Java6 Arrays.copyOfRange style method locally. * * @param original the array to copy * @param start the start of the copy range * @param end the end of the copy range * @return a new array populated with the bytes from original[start] to original[end]. */ private static byte[] copyOfRange(byte[] original, int start, int end) { final byte[] copy = new byte[end-start]; System.arraycopy(original, start, copy, 0, end-start); return copy; } /** * Parse a block of header lines as defined here: * * http://tools.ietf.org/html/rfc822#section-3.2 * * @param s * The header blob * @return Map of header names to values */ public static Map parseHeaders(String s) { // "unfold" header lines (http://tools.ietf.org/html/rfc822#section-3.1) s.replaceAll("\r\n\\s+", " "); String[] headers = s.split("\r\n"); Map parsedHeaders = new HashMap(); for (String header : headers) { // Split header line into name and value String[] nv = header.split("\\s*:\\s*", 2); if (nv.length > 1) { parsedHeaders.put(nv[0].trim().toLowerCase(), nv[1].trim()); } } return parsedHeaders; } /** * Given a content type value, get the "boundary" parameter * * @param contentType * Content type value with boundary parameter. Should be of the * form "type/subtype; boundary=foobar; param=value" * @return Value of the boundary parameter */ public static String getBoundary(String contentType) { String[] params = contentType.split("\\s*;\\s*"); for (String param : params) { String[] nv = param.split("\\s*=\\s*", 2); if (nv.length > 1) { if ("boundary".equals(nv[0].toLowerCase())) return ClientUtils.unquoteString(nv[1]); } } return ""; } /** * A single part of a multipart entity * * @deprecated with the addition of a protocol buffers client in 0.14 all * the existing REST client code should be in client.http.* this * class has therefore been moved. Please use * com.basho.riak.client.http.util.ClientHelper instead. *

* WARNING: This class will be REMOVED in the next version. *

* @see com.basho.riak.client.http.util.Multipart.Part */ @Deprecated public static class Part { private Map headers; private byte[] body = null; private InputStream stream; public Part(Map headers, byte[] body) { this.headers = headers; if(body != null) { this.body = body.clone(); } } public Part(Map headers, InputStream body) { this.headers = headers; stream = body; } /** * Headers defined in the part */ public Map getHeaders() { return headers; } /** * Body of this part */ public byte[] getBody() { if (body == null && stream != null) { try { ByteArrayOutputStream os = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; for (int readCount = 0; readCount != -1; readCount = stream.read(buffer)) { os.write(buffer, 0, readCount); } body = os.toByteArray(); } catch (IOException e) { /* nop */} stream = null; } return body; } public String getBodyAsString() { byte[] body = getBody(); if (body == null) return null; return asString(body, getCharset(headers)); } public InputStream getStream() { if (stream == null && body != null) { stream = new ByteArrayInputStream(body); } return stream; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy