145 lines
4.4 KiB
Java
145 lines
4.4 KiB
Java
package com.jenkov.nioserver.http;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
/**
|
|
* Project: <strong>java-nio-server</strong><br>
|
|
* File: <strong>HttpUtil.java</strong><br>
|
|
* Created: <strong>19 Oct 2015</strong><br>
|
|
*
|
|
* @author jjenkov
|
|
*/
|
|
public class HttpUtil {
|
|
|
|
private static final byte[] GET = new byte[] { 'G', 'E', 'T' };
|
|
private static final byte[] POST = new byte[] { 'P', 'O', 'S', 'T' };
|
|
private static final byte[] PUT = new byte[] { 'P', 'U', 'T' };
|
|
private static final byte[] HEAD = new byte[] { 'H', 'E', 'A', 'D' };
|
|
private static final byte[] DELETE = new byte[] { 'D', 'E', 'L', 'E', 'T', 'E' };
|
|
|
|
@SuppressWarnings("unused")
|
|
private static final byte[] HOST = new byte[] { 'H', 'o', 's', 't' };
|
|
private static final byte[] CONTENT_LENGTH = new byte[] { 'C', 'o', 'n', 't', 'e', 'n', 't', '-', 'L', 'e', 'n', 'g', 't', 'h' };
|
|
|
|
public static int parseHttpRequest(byte[] src, int startIndex, int endIndex, HttpHeaders httpHeaders) {
|
|
|
|
/*
|
|
* int endOfHttpMethod = findNext(src, startIndex, endIndex, (byte) ' ');
|
|
* if(endOfHttpMethod == -1) return false;
|
|
* resolveHttpMethod(src, startIndex, httpHeaders);
|
|
*/
|
|
|
|
// parse HTTP request line
|
|
int endOfFirstLine = findNextLineBreak(src, startIndex, endIndex);
|
|
if (endOfFirstLine == -1) return -1;
|
|
|
|
// parse HTTP headers
|
|
int prevEndOfHeader = endOfFirstLine + 1;
|
|
int endOfHeader = findNextLineBreak(src, prevEndOfHeader, endIndex);
|
|
|
|
while (endOfHeader != -1 && endOfHeader != prevEndOfHeader + 1) { // prevEndOfHeader + 1 = end of previous header + 2 (+2 = CR + LF)
|
|
|
|
if (matches(src, prevEndOfHeader, CONTENT_LENGTH)) {
|
|
try {
|
|
findContentLength(src, prevEndOfHeader, endIndex, httpHeaders);
|
|
} catch (UnsupportedEncodingException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
prevEndOfHeader = endOfHeader + 1;
|
|
endOfHeader = findNextLineBreak(src, prevEndOfHeader, endIndex);
|
|
}
|
|
|
|
if (endOfHeader == -1) { return -1; }
|
|
|
|
// check that byte array contains full HTTP message.
|
|
int bodyStartIndex = endOfHeader + 1;
|
|
int bodyEndIndex = bodyStartIndex + httpHeaders.contentLength;
|
|
|
|
if (bodyEndIndex <= endIndex) {
|
|
// byte array contains a full HTTP request
|
|
httpHeaders.bodyStartIndex = bodyStartIndex;
|
|
httpHeaders.bodyEndIndex = bodyEndIndex;
|
|
return bodyEndIndex;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
private static void findContentLength(byte[] src, int startIndex, int endIndex, HttpHeaders httpHeaders) throws UnsupportedEncodingException {
|
|
int indexOfColon = findNext(src, startIndex, endIndex, (byte) ':');
|
|
|
|
// skip spaces after colon
|
|
int index = indexOfColon + 1;
|
|
while (src[index] == ' ') {
|
|
index++;
|
|
}
|
|
|
|
int valueStartIndex = index;
|
|
int valueEndIndex = index;
|
|
boolean endOfValueFound = false;
|
|
|
|
while (index < endIndex && !endOfValueFound) {
|
|
switch (src[index]) {
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
index++;
|
|
break;
|
|
default:
|
|
endOfValueFound = true;
|
|
valueEndIndex = index;
|
|
}
|
|
}
|
|
httpHeaders.contentLength = Integer.parseInt(new String(src, valueStartIndex, valueEndIndex - valueStartIndex, "UTF-8"));
|
|
}
|
|
|
|
public static int findNext(byte[] src, int startIndex, int endIndex, byte value) {
|
|
for (int index = startIndex; index < endIndex; index++)
|
|
if (src[index] == value) return index;
|
|
return -1;
|
|
}
|
|
|
|
public static int findNextLineBreak(byte[] src, int startIndex, int endIndex) {
|
|
for (int index = startIndex; index < endIndex; index++)
|
|
if (src[index] == '\n') if (src[index - 1] == '\r') return index;
|
|
return -1;
|
|
}
|
|
|
|
public static void resolveHttpMethod(byte[] src, int startIndex, HttpHeaders httpHeaders) {
|
|
if (matches(src, startIndex, GET)) {
|
|
httpHeaders.httpMethod = HttpHeaders.HTTP_METHOD_GET;
|
|
return;
|
|
}
|
|
if (matches(src, startIndex, POST)) {
|
|
httpHeaders.httpMethod = HttpHeaders.HTTP_METHOD_POST;
|
|
return;
|
|
}
|
|
if (matches(src, startIndex, PUT)) {
|
|
httpHeaders.httpMethod = HttpHeaders.HTTP_METHOD_PUT;
|
|
return;
|
|
}
|
|
if (matches(src, startIndex, HEAD)) {
|
|
httpHeaders.httpMethod = HttpHeaders.HTTP_METHOD_HEAD;
|
|
return;
|
|
}
|
|
if (matches(src, startIndex, DELETE)) {
|
|
httpHeaders.httpMethod = HttpHeaders.HTTP_METHOD_DELETE;
|
|
return;
|
|
}
|
|
}
|
|
|
|
public static boolean matches(byte[] src, int offset, byte[] value) {
|
|
for (int i = offset, n = 0; n < value.length; i++, n++)
|
|
if (src[i] != value[n]) return false;
|
|
return true;
|
|
}
|
|
} |