Search in sources :

Example 1 with ResponseException

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);
    }
}
Also used : DataOutput(java.io.DataOutput) RandomAccessFile(java.io.RandomAccessFile) ContentType(org.nanohttpd.protocols.http.content.ContentType) ResponseException(org.nanohttpd.protocols.http.NanoHTTPD.ResponseException) DataOutputStream(java.io.DataOutputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ByteBuffer(java.nio.ByteBuffer)

Example 2 with ResponseException

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();
    }
}
Also used : SocketException(java.net.SocketException) InputStreamReader(java.io.InputStreamReader) HashMap(java.util.HashMap) ResponseException(org.nanohttpd.protocols.http.NanoHTTPD.ResponseException) IOException(java.io.IOException) SSLException(javax.net.ssl.SSLException) Response(org.nanohttpd.protocols.http.response.Response) SocketTimeoutException(java.net.SocketTimeoutException) ByteArrayInputStream(java.io.ByteArrayInputStream) BufferedReader(java.io.BufferedReader) ArrayList(java.util.ArrayList) List(java.util.List) CookieHandler(org.nanohttpd.protocols.http.content.CookieHandler)

Example 3 with ResponseException

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());
    }
}
Also used : InputStreamReader(java.io.InputStreamReader) ResponseException(org.nanohttpd.protocols.http.NanoHTTPD.ResponseException) ByteArrayInputStream(java.io.ByteArrayInputStream) Matcher(java.util.regex.Matcher) BufferedReader(java.io.BufferedReader) ResponseException(org.nanohttpd.protocols.http.NanoHTTPD.ResponseException) SocketException(java.net.SocketException) SocketTimeoutException(java.net.SocketTimeoutException) IOException(java.io.IOException) SSLException(javax.net.ssl.SSLException)

Example 4 with ResponseException

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);
    }
}
Also used : StringTokenizer(java.util.StringTokenizer) ResponseException(org.nanohttpd.protocols.http.NanoHTTPD.ResponseException) IOException(java.io.IOException)

Aggregations

ResponseException (org.nanohttpd.protocols.http.NanoHTTPD.ResponseException)4 IOException (java.io.IOException)3 BufferedReader (java.io.BufferedReader)2 ByteArrayInputStream (java.io.ByteArrayInputStream)2 InputStreamReader (java.io.InputStreamReader)2 SocketException (java.net.SocketException)2 SocketTimeoutException (java.net.SocketTimeoutException)2 SSLException (javax.net.ssl.SSLException)2 ByteArrayOutputStream (java.io.ByteArrayOutputStream)1 DataOutput (java.io.DataOutput)1 DataOutputStream (java.io.DataOutputStream)1 RandomAccessFile (java.io.RandomAccessFile)1 ByteBuffer (java.nio.ByteBuffer)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 List (java.util.List)1 StringTokenizer (java.util.StringTokenizer)1 Matcher (java.util.regex.Matcher)1 ContentType (org.nanohttpd.protocols.http.content.ContentType)1 CookieHandler (org.nanohttpd.protocols.http.content.CookieHandler)1