com.hazelcast.internal.ascii.rest.HttpPostCommand Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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.hazelcast.internal.ascii.rest;
import com.hazelcast.internal.ascii.NoOpCommand;
import com.hazelcast.nio.IOUtil;
import com.hazelcast.nio.ascii.TextReadHandler;
import com.hazelcast.util.StringUtil;
import java.nio.ByteBuffer;
import static com.hazelcast.internal.ascii.TextCommandConstants.TextCommandType.HTTP_POST;
import static com.hazelcast.util.StringUtil.stringToBytes;
public class HttpPostCommand extends HttpCommand {
private static final int RADIX = 16;
private static final int CAPACITY = 500;
boolean nextLine;
boolean readyToReadData;
private ByteBuffer data;
private ByteBuffer line = ByteBuffer.allocate(CAPACITY);
private String contentType;
private final TextReadHandler readHandler;
private boolean chunked;
public HttpPostCommand(TextReadHandler readHandler, String uri) {
super(HTTP_POST, uri);
this.readHandler = readHandler;
}
/**
* POST /path HTTP/1.0
* User-Agent: HTTPTool/1.0
* Content-TextCommandType: application/x-www-form-urlencoded
* Content-Length: 45
*
*
* byte[45]
*
*
* @param src
* @return
*/
@Override
public boolean readFrom(ByteBuffer src) {
boolean complete = doActualRead(src);
while (!complete && readyToReadData && chunked && src.hasRemaining()) {
complete = doActualRead(src);
}
if (complete) {
if (data != null) {
data.flip();
}
}
return complete;
}
public byte[] getData() {
if (data == null) {
return null;
} else {
return data.array();
}
}
public byte[] getContentType() {
if (contentType == null) {
return null;
} else {
return stringToBytes(contentType);
}
}
private void dataNullCheck(int dataSize) {
if (data != null) {
ByteBuffer newData = ByteBuffer.allocate(data.capacity() + dataSize);
newData.put(data.array());
data = newData;
} else {
data = ByteBuffer.allocate(dataSize);
}
}
private void setReadyToReadData(ByteBuffer cb) {
while (!readyToReadData && cb.hasRemaining()) {
byte b = cb.get();
char c = (char) b;
if (c == '\n') {
processLine(StringUtil.lowerCaseInternal(toStringAndClear(line)));
if (nextLine) {
readyToReadData = true;
}
nextLine = true;
} else if (c != '\r') {
nextLine = false;
line.put(b);
}
}
}
public boolean doActualRead(ByteBuffer cb) {
if (readyToReadData) {
if (chunked && (data == null || !data.hasRemaining())) {
boolean done = readLine(cb);
if (done) {
return true;
}
}
IOUtil.copyToHeapBuffer(cb, data);
}
setReadyToReadData(cb);
return !chunked && ((data != null) && !data.hasRemaining());
}
String toStringAndClear(ByteBuffer bb) {
if (bb == null) {
return "";
}
String result;
if (bb.position() == 0) {
result = "";
} else {
result = StringUtil.bytesToString(bb.array(), 0, bb.position());
}
bb.clear();
return result;
}
boolean readLine(ByteBuffer cb) {
boolean hasLine = false;
while (cb.hasRemaining()) {
byte b = cb.get();
char c = (char) b;
if (c == '\n') {
hasLine = true;
} else if (c != '\r') {
line.put(b);
}
}
if (hasLine) {
String lineStr = toStringAndClear(line).trim();
// hex string
int dataSize = lineStr.length() == 0 ? 0 : Integer.parseInt(lineStr, RADIX);
if (dataSize == 0) {
return true;
}
dataNullCheck(dataSize);
}
return false;
}
private void processLine(String currentLine) {
if (contentType == null && currentLine.startsWith(HEADER_CONTENT_TYPE)) {
contentType = currentLine.substring(currentLine.indexOf(' ') + 1);
} else if (data == null && currentLine.startsWith(HEADER_CONTENT_LENGTH)) {
data = ByteBuffer.allocate(Integer.parseInt(currentLine.substring(currentLine.indexOf(' ') + 1)));
} else if (!chunked && currentLine.startsWith(HEADER_CHUNKED)) {
chunked = true;
} else if (currentLine.startsWith(HEADER_EXPECT_100)) {
readHandler.sendResponse(new NoOpCommand(RES_100));
}
}
}