use of org.nanohttpd.protocols.http.NanoHTTPD.ResponseException in project nanohttpd by NanoHttpd.
the class HTTPSession method parseBody.
@Override
public void parseBody(Map<String, String> files) throws IOException, ResponseException {
RandomAccessFile randomAccessFile = null;
try {
long size = getBodySize();
ByteArrayOutputStream baos = null;
DataOutput requestDataOutput = null;
// Store the request in memory or a file, depending on size
if (size < MEMORY_STORE_LIMIT) {
baos = new ByteArrayOutputStream();
requestDataOutput = new DataOutputStream(baos);
} else {
randomAccessFile = getTmpBucket();
requestDataOutput = randomAccessFile;
}
// Read all the body and write it to request_data_output
byte[] buf = new byte[REQUEST_BUFFER_LEN];
while (this.rlen >= 0 && size > 0) {
this.rlen = this.inputStream.read(buf, 0, (int) Math.min(size, REQUEST_BUFFER_LEN));
size -= this.rlen;
if (this.rlen > 0) {
requestDataOutput.write(buf, 0, this.rlen);
}
}
ByteBuffer fbuf = null;
if (baos != null) {
fbuf = ByteBuffer.wrap(baos.toByteArray(), 0, baos.size());
} else {
fbuf = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length());
randomAccessFile.seek(0);
}
// in data section, too, read it:
if (Method.POST.equals(this.method)) {
ContentType contentType = new ContentType(this.headers.get("content-type"));
if (contentType.isMultipart()) {
String boundary = contentType.getBoundary();
if (boundary == null) {
throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html");
}
decodeMultipartFormData(contentType, fbuf, this.parms, files);
} else {
byte[] postBytes = new byte[fbuf.remaining()];
fbuf.get(postBytes);
String postLine = new String(postBytes, contentType.getEncoding()).trim();
// Handle application/x-www-form-urlencoded
if ("application/x-www-form-urlencoded".equalsIgnoreCase(contentType.getContentType())) {
decodeParms(postLine, this.parms);
} else if (postLine.length() != 0) {
// Special case for raw POST data => create a
// special files entry "postData" with raw content
// data
files.put(POST_DATA, postLine);
}
}
} else if (Method.PUT.equals(this.method)) {
files.put("content", saveTmpFile(fbuf, 0, fbuf.limit(), null));
}
} finally {
NanoHTTPD.safeClose(randomAccessFile);
}
}
use of org.nanohttpd.protocols.http.NanoHTTPD.ResponseException in project nanohttpd by NanoHttpd.
the class HTTPSession method execute.
@Override
public void execute() throws IOException {
Response r = null;
try {
// Read the first 8192 bytes.
// The full header should fit in here.
// Apache's default header limit is 8KB.
// Do NOT assume that a single read will get the entire header
// at once!
byte[] buf = new byte[HTTPSession.BUFSIZE];
this.splitbyte = 0;
this.rlen = 0;
int read = -1;
this.inputStream.mark(HTTPSession.BUFSIZE);
try {
read = this.inputStream.read(buf, 0, HTTPSession.BUFSIZE);
} catch (SSLException e) {
throw e;
} catch (IOException e) {
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.outputStream);
throw new SocketException("NanoHttpd Shutdown");
}
if (read == -1) {
// socket was been closed
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.outputStream);
throw new SocketException("NanoHttpd Shutdown");
}
while (read > 0) {
this.rlen += read;
this.splitbyte = findHeaderEnd(buf, this.rlen);
if (this.splitbyte > 0) {
break;
}
read = this.inputStream.read(buf, this.rlen, HTTPSession.BUFSIZE - this.rlen);
}
if (this.splitbyte < this.rlen) {
this.inputStream.reset();
this.inputStream.skip(this.splitbyte);
}
this.parms = new HashMap<String, List<String>>();
if (null == this.headers) {
this.headers = new HashMap<String, String>();
} else {
this.headers.clear();
}
// Create a BufferedReader for parsing the header.
BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, this.rlen)));
// Decode the header into parms and header java properties
Map<String, String> pre = new HashMap<String, String>();
decodeHeader(hin, pre, this.parms, this.headers);
if (null != this.remoteIp) {
this.headers.put("remote-addr", this.remoteIp);
this.headers.put("http-client-ip", this.remoteIp);
}
this.method = Method.lookup(pre.get("method"));
if (this.method == null) {
throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Syntax error. HTTP verb " + pre.get("method") + " unhandled.");
}
this.uri = pre.get("uri");
this.cookies = new CookieHandler(this.headers);
String connection = this.headers.get("connection");
boolean keepAlive = "HTTP/1.1".equals(protocolVersion) && (connection == null || !connection.matches("(?i).*close.*"));
// Ok, now do the serve()
// TODO: long body_size = getBodySize();
// TODO: long pos_before_serve = this.inputStream.totalRead()
// (requires implementation for totalRead())
r = httpd.handle(this);
if (r == null) {
throw new ResponseException(Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: Serve() returned a null response.");
} else {
String acceptEncoding = this.headers.get("accept-encoding");
this.cookies.unloadQueue(r);
r.setRequestMethod(this.method);
if (acceptEncoding == null || !acceptEncoding.contains("gzip")) {
r.setUseGzip(false);
}
r.setKeepAlive(keepAlive);
r.send(this.outputStream);
}
if (!keepAlive || r.isCloseConnection()) {
throw new SocketException("NanoHttpd Shutdown");
}
} catch (SocketException e) {
// throw it out to close socket object (finalAccept)
throw e;
} catch (SocketTimeoutException ste) {
// exception up the call stack.
throw ste;
} catch (SSLException ssle) {
Response resp = Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "SSL PROTOCOL FAILURE: " + ssle.getMessage());
resp.send(this.outputStream);
NanoHTTPD.safeClose(this.outputStream);
} catch (IOException ioe) {
Response resp = Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
resp.send(this.outputStream);
NanoHTTPD.safeClose(this.outputStream);
} catch (ResponseException re) {
Response resp = Response.newFixedLengthResponse(re.getStatus(), NanoHTTPD.MIME_PLAINTEXT, re.getMessage());
resp.send(this.outputStream);
NanoHTTPD.safeClose(this.outputStream);
} finally {
NanoHTTPD.safeClose(r);
this.tempFileManager.clear();
}
}
use of org.nanohttpd.protocols.http.NanoHTTPD.ResponseException in project nanohttpd by NanoHttpd.
the class HTTPSession method decodeMultipartFormData.
/**
* Decodes the Multipart Body data and put it into Key/Value pairs.
*/
private void decodeMultipartFormData(ContentType contentType, ByteBuffer fbuf, Map<String, List<String>> parms, Map<String, String> files) throws ResponseException {
int pcount = 0;
try {
int[] boundaryIdxs = getBoundaryPositions(fbuf, contentType.getBoundary().getBytes());
if (boundaryIdxs.length < 2) {
throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but contains less than two boundary strings.");
}
byte[] partHeaderBuff = new byte[MAX_HEADER_SIZE];
for (int boundaryIdx = 0; boundaryIdx < boundaryIdxs.length - 1; boundaryIdx++) {
fbuf.position(boundaryIdxs[boundaryIdx]);
int len = (fbuf.remaining() < MAX_HEADER_SIZE) ? fbuf.remaining() : MAX_HEADER_SIZE;
fbuf.get(partHeaderBuff, 0, len);
BufferedReader in = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(partHeaderBuff, 0, len), Charset.forName(contentType.getEncoding())), len);
int headerLines = 0;
// First line is boundary string
String mpline = in.readLine();
headerLines++;
if (mpline == null || !mpline.contains(contentType.getBoundary())) {
throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but chunk does not start with boundary.");
}
String partName = null, fileName = null, partContentType = null;
// Parse the reset of the header lines
mpline = in.readLine();
headerLines++;
while (mpline != null && mpline.trim().length() > 0) {
Matcher matcher = NanoHTTPD.CONTENT_DISPOSITION_PATTERN.matcher(mpline);
if (matcher.matches()) {
String attributeString = matcher.group(2);
matcher = NanoHTTPD.CONTENT_DISPOSITION_ATTRIBUTE_PATTERN.matcher(attributeString);
while (matcher.find()) {
String key = matcher.group(1);
if ("name".equalsIgnoreCase(key)) {
partName = matcher.group(2);
} else if ("filename".equalsIgnoreCase(key)) {
fileName = matcher.group(2);
// files uploaded using the same field Id
if (!fileName.isEmpty()) {
if (pcount > 0)
partName = partName + String.valueOf(pcount++);
else
pcount++;
}
}
}
}
matcher = NanoHTTPD.CONTENT_TYPE_PATTERN.matcher(mpline);
if (matcher.matches()) {
partContentType = matcher.group(2).trim();
}
mpline = in.readLine();
headerLines++;
}
int partHeaderLength = 0;
while (headerLines-- > 0) {
partHeaderLength = scipOverNewLine(partHeaderBuff, partHeaderLength);
}
// Read the part data
if (partHeaderLength >= len - 4) {
throw new ResponseException(Status.INTERNAL_ERROR, "Multipart header size exceeds MAX_HEADER_SIZE.");
}
int partDataStart = boundaryIdxs[boundaryIdx] + partHeaderLength;
int partDataEnd = boundaryIdxs[boundaryIdx + 1] - 4;
fbuf.position(partDataStart);
List<String> values = parms.get(partName);
if (values == null) {
values = new ArrayList<String>();
parms.put(partName, values);
}
if (partContentType == null) {
// Read the part into a string
byte[] data_bytes = new byte[partDataEnd - partDataStart];
fbuf.get(data_bytes);
values.add(new String(data_bytes, contentType.getEncoding()));
} else {
// Read it into a file
String path = saveTmpFile(fbuf, partDataStart, partDataEnd - partDataStart, fileName);
if (!files.containsKey(partName)) {
files.put(partName, path);
} else {
int count = 2;
while (files.containsKey(partName + count)) {
count++;
}
files.put(partName + count, path);
}
values.add(fileName);
}
}
} catch (ResponseException re) {
throw re;
} catch (Exception e) {
throw new ResponseException(Status.INTERNAL_ERROR, e.toString());
}
}
use of org.nanohttpd.protocols.http.NanoHTTPD.ResponseException in project nanohttpd by NanoHttpd.
the class HTTPSession method decodeHeader.
/**
* Decodes the sent headers and loads the data into Key/value pairs
*/
private void decodeHeader(BufferedReader in, Map<String, String> pre, Map<String, List<String>> parms, Map<String, String> headers) throws ResponseException {
try {
// Read the request line
String inLine = in.readLine();
if (inLine == null) {
return;
}
StringTokenizer st = new StringTokenizer(inLine);
if (!st.hasMoreTokens()) {
throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html");
}
pre.put("method", st.nextToken());
if (!st.hasMoreTokens()) {
throw new ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Missing URI. Usage: GET /example/file.html");
}
String uri = st.nextToken();
// Decode parameters from the URI
int qmi = uri.indexOf('?');
if (qmi >= 0) {
decodeParms(uri.substring(qmi + 1), parms);
uri = NanoHTTPD.decodePercent(uri.substring(0, qmi));
} else {
uri = NanoHTTPD.decodePercent(uri);
}
// case insensitive and vary by client.
if (st.hasMoreTokens()) {
protocolVersion = st.nextToken();
} else {
protocolVersion = "HTTP/1.1";
NanoHTTPD.LOG.log(Level.FINE, "no protocol version specified, strange. Assuming HTTP/1.1.");
}
String line = in.readLine();
while (line != null && !line.trim().isEmpty()) {
int p = line.indexOf(':');
if (p >= 0) {
headers.put(line.substring(0, p).trim().toLowerCase(Locale.US), line.substring(p + 1).trim());
}
line = in.readLine();
}
pre.put("uri", uri);
} catch (IOException ioe) {
throw new ResponseException(Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage(), ioe);
}
}
Aggregations