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

com.koushikdutta.async.http.server.BoundaryEmitter Maven / Gradle / Ivy

Go to download

Asynchronous socket, http(s) (client+server) and websocket library for android. Based on nio, not threads.

There is a newer version: 3.1.0
Show newest version
package com.koushikdutta.async.http.server;

import android.util.Log;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.FilteredDataEmitter;

import java.nio.ByteBuffer;

public class BoundaryEmitter extends FilteredDataEmitter {
    private byte[] boundary;
    public void setBoundary(String boundary) {
        this.boundary = ("\r\n--" + boundary).getBytes();
    }
    
    public String getBoundary() {
        if (boundary == null)
            return null;
        return new String(boundary, 4, boundary.length - 4);
    }
    
    public String getBoundaryStart() {
        assert boundary != null;
        return new String(boundary, 2, boundary.length - 2);
    }
    
    public String getBoundaryEnd() {
        assert boundary != null;
        return getBoundaryStart() + "--\r\n";
    }
    
    protected void onBoundaryStart() {
    }
    
    protected void onBoundaryEnd() {
    }
    
    // >= 0 matching
    // -1 matching - (start of boundary end) or \r (boundary start)
    // -2 matching - (end of boundary end)
    // -3 matching \r after boundary
    // -4 matching \n after boundary

    // the state starts out having already matched \r\n

    /*
        Content-Type: multipart/form-data; boundary=----------------------------bc3c801ac760
        
        ------------------------------bc3c801ac760
        Content-Disposition: form-data; name="my-file"; filename="foo"
        Content-Type: application/octet-stream
        
        foo         <---------------- the newline is NOT PART OF THE PAYLOAD
        ------------------------------bc3c801ac760--
     */
    
    
    int state = 2;
    @Override
    public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
//        System.out.println(bb.getString());
//        System.out.println("chunk: " + bb.remaining());
        
//        System.out.println("state: " + state);
        
        // if we were in the middle of a potential match, let's throw that
        // at the beginning of the buffer and process it too.
        if (state > 0) {
            ByteBuffer b = ByteBuffer.wrap(boundary, 0, state).duplicate();
            bb.add(0, b);
            state = 0;
        }
        
        int last = 0;
        byte[] buf = new byte[bb.remaining()];
        bb.get(buf);
        for (int i = 0; i < buf.length; i++) {
            if (state >= 0) {
                if (buf[i] == boundary[state]) {
                    state++;
                    if (state == boundary.length)
                        state = -1;
                }
                else if (state > 0) {
                    // let's try matching again one byte after the start
                    // of last match occurrence
                    i -= state;
                    state = 0;
                }
            }
            else if (state == -1) {
                if (buf[i] == '\r') {
                    state = -4;
                    int len = i - last - boundary.length;
                    if (last != 0 || len != 0) {
                        ByteBuffer b = ByteBuffer.wrap(buf, last, len);
                        ByteBufferList list = new ByteBufferList();
                        list.add(b);
                        super.onDataAvailable(this, list);
                    }
//                    System.out.println("bstart");
                    onBoundaryStart();
                }
                else if (buf[i] == '-') {
                    state = -2;
                }
                else {
                    report(new Exception("Invalid multipart/form-data. Expected \r or -"));
                    return;
                }
            }
            else if (state == -2) {
                if (buf[i] == '-') {
                    state = -3;
                }
                else {
                    report(new Exception("Invalid multipart/form-data. Expected -"));
                    return;
                }
            }
            else if (state == -3) {
                if (buf[i] == '\r') {
                    state = -4;
                    ByteBuffer b = ByteBuffer.wrap(buf, last, i - last - boundary.length - 2);
                    ByteBufferList list = new ByteBufferList();
                    list.add(b);
                    super.onDataAvailable(this, list);
//                    System.out.println("bend");
                    onBoundaryEnd();
                }
                else {
                    report(new Exception("Invalid multipart/form-data. Expected \r"));
                    return;
                }
            }
            else if (state == -4) {
                if (buf[i] == '\n') {
                    last = i + 1;
                    state = 0;
                }
                else {
                    report(new Exception("Invalid multipart/form-data. Expected \n"));
                }
            }
            else {
                assert false;
                report(new Exception("Invalid multipart/form-data. Unknown state?"));
            }
        }

        if (last < buf.length) {
//            System.out.println("amount left at boundary: " + (buf.length - last));
//            System.out.println("State: " + state);
//            System.out.println(state);
            int keep = Math.max(state, 0);
            ByteBuffer b = ByteBuffer.wrap(buf, last, buf.length - last - keep);
            ByteBufferList list = new ByteBufferList();
            list.add(b);
            super.onDataAvailable(this, list);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy