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

com.firefly.codec.http2.model.InclusiveByteRange Maven / Gradle / Ivy

There is a newer version: 5.0.0-dev6
Show newest version
//
//  ========================================================================
//  Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package com.firefly.codec.http2.model;


import com.firefly.utils.collection.LazyList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.StringTokenizer;


/**
 * Byte range inclusive of end points.
 * <PRE>
 * parses the following types of byte ranges:
 * bytes=100-499
 * bytes=-300
 * bytes=100-
 * bytes=1-2,2-3,6-,-2
 * given an entity length, converts range to string
 * bytes 100-499/500
 * </PRE>
 * Based on RFC2616 3.12, 14.16, 14.35.1, 14.35.2
 * And yes the spec does strangely say that while 10-20, is bytes 10 to 20 and 10- is bytes 10 until the end that -20 IS NOT bytes 0-20, but the last 20 bytes of the content.
 *
 * @version $version$
 */
public class InclusiveByteRange {
    private static Logger log = LoggerFactory.getLogger("firefly-system");

    long first = 0;
    long last = 0;

    public InclusiveByteRange(long first, long last) {
        this.first = first;
        this.last = last;
    }

    public long getFirst() {
        return first;
    }

    public long getLast() {
        return last;
    }

    /**
     * @param headers Enumeration of Range header fields.
     * @param size    Size of the resource.
     * @return LazyList of satisfiable ranges
     */
    public static List satisfiableRanges(List headers, long size) {
        Object satRanges = null;

        // walk through all Range headers
        headers:
        for (String header : headers) {
            StringTokenizer tok = new StringTokenizer(header, "=,", false);
            String t = null;
            try {
                // read all byte ranges for this header 
                while (tok.hasMoreTokens()) {
                    try {
                        t = tok.nextToken().trim();

                        long first = -1;
                        long last = -1;
                        int d = t.indexOf('-');
                        if (d < 0 || t.indexOf("-", d + 1) >= 0) {
                            if ("bytes".equals(t))
                                continue;
                            log.warn("Bad range format: {}", t);
                            continue headers;
                        } else if (d == 0) {
                            if (d + 1 < t.length())
                                last = Long.parseLong(t.substring(d + 1).trim());
                            else {
                                log.warn("Bad range format: {}", t);
                                continue;
                            }
                        } else if (d + 1 < t.length()) {
                            first = Long.parseLong(t.substring(0, d).trim());
                            last = Long.parseLong(t.substring(d + 1).trim());
                        } else
                            first = Long.parseLong(t.substring(0, d).trim());

                        if (first == -1 && last == -1)
                            continue headers;

                        if (first != -1 && last != -1 && (first > last))
                            continue headers;

                        if (first < size) {
                            InclusiveByteRange range = new InclusiveByteRange(first, last);
                            satRanges = LazyList.add(satRanges, range);
                        }
                    } catch (NumberFormatException e) {
                        log.warn("Bad range format: {}", t);
                        continue;
                    }
                }
            } catch (Exception e) {
                log.warn("Bad range format: {}", t);
            }
        }
        return LazyList.getList(satRanges, true);
    }

    public long getFirst(long size) {
        if (first < 0) {
            long tf = size - last;
            if (tf < 0)
                tf = 0;
            return tf;
        }
        return first;
    }

    public long getLast(long size) {
        if (first < 0)
            return size - 1;

        if (last < 0 || last >= size)
            return size - 1;
        return last;
    }

    public long getSize(long size) {
        return getLast(size) - getFirst(size) + 1;
    }

    public String toHeaderRangeString(long size) {
        StringBuilder sb = new StringBuilder(40);
        sb.append("bytes ");
        sb.append(getFirst(size));
        sb.append('-');
        sb.append(getLast(size));
        sb.append("/");
        sb.append(size);
        return sb.toString();
    }

    public static String to416HeaderRangeString(long size) {
        StringBuilder sb = new StringBuilder(40);
        sb.append("bytes */");
        sb.append(size);
        return sb.toString();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(60);
        sb.append(Long.toString(first));
        sb.append(":");
        sb.append(Long.toString(last));
        return sb.toString();
    }

}







© 2015 - 2025 Weber Informatics LLC | Privacy Policy