/**
* personium.io
* Copyright 2014 FUJITSU LIMITED
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.fujitsu.dc.core.http.header;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* ByteRangeSpecを管理するための入れ物.
*/
public class ByteRangeSpec {
private long entitySize;
private long firstBytePos;
private long lastBytePos;
private ByteRangeSpec(final long firstBytePos, final long lastBytePos, final long entitySize) {
this.entitySize = entitySize;
this.firstBytePos = firstBytePos;
this.lastBytePos = lastBytePos;
}
/**
* byte-range-specをパースして構文上正しければ本オブジェクトを返す. 不正な場合はnullを返す.
* @param byteRangeSpecString byte-range-specの文字列
* @param entitySize Range対象のファイルサイズ
* @return 本オブジェクト
*/
static final ByteRangeSpec parse(final String byteRangeSpecString, final long entitySize) {
String firstBytePosString;
String lastBytePosString;
long firstBytePosLong;
long lastBytePosLong;
// 開始、終端の取得
String regexByteRangeSpec = "^([^-]*)-([^-]*)$";
Pattern pByteRangeSpec = Pattern.compile(regexByteRangeSpec);
Matcher mByteRangeSpec = pByteRangeSpec.matcher(byteRangeSpecString);
if (!mByteRangeSpec.matches()) {
return null;
}
firstBytePosString = mByteRangeSpec.group(1).trim();
lastBytePosString = mByteRangeSpec.group(2).trim();
// 開始、終端両方省略されてる場合は無効
if (firstBytePosString.equals("") && lastBytePosString.equals("")) {
return null;
}
if (lastBytePosString.equals("")) {
// 終端が省略されている場合はファイルサイズまでを終端とする
lastBytePosLong = entitySize - 1;
} else {
try {
lastBytePosLong = Long.parseLong(lastBytePosString);
} catch (NumberFormatException e) {
return null;
}
}
// 開始省略されてて終端の指定があったら(最後-終端)から最後まで
if (firstBytePosString.equals("")) {
firstBytePosLong = entitySize - lastBytePosLong;
if (firstBytePosLong < 0) {
firstBytePosLong = 0;
}
lastBytePosLong = entitySize - 1;
} else {
// 数値かどうかチェック
try {
firstBytePosLong = Long.parseLong(firstBytePosString);
} catch (NumberFormatException e) {
return null;
}
}
// Rangeの開始と終端の位置が反転してたらRangeヘッダ無効
if (firstBytePosLong > lastBytePosLong) {
return null;
}
// 終端がエンティティサイズより大きい場合は、終端の値はエンティティサイズ-1の値
if (lastBytePosLong >= entitySize) {
lastBytePosLong = entitySize - 1;
}
return new ByteRangeSpec(firstBytePosLong, lastBytePosLong, entitySize);
}
/**
* Rangeの開始位置がファイルの範囲内かチェックして範囲内の場合はtrue返す.
* @return bool
*/
public boolean isInEntitySize() {
if (this.getFirstBytePos() > (this.entitySize - 1)) {
return false;
}
return true;
}
/**
* first-byte-pos.
* @return first-byte-pos
*/
public long getFirstBytePos() {
return this.firstBytePos;
}
/**
* last-byte-pos.
* @return last-byte-pos
*/
public long getLastBytePos() {
return this.lastBytePos;
}
/**
* Rangeの指定を考慮したContentLengthの返却.
* @return long contentLength
*/
public long getContentLength() {
return this.getLastBytePos() + 1 - this.getFirstBytePos();
}
/**
* Rangeの値をContent-Rangeヘッダの値に整形.
* @return Content-Rangeヘッダの値
*/
public String makeContentRangeHeaderField() {
// Content-Rangeヘッダのフォーマットで返す
return String.format("bytes %s-%s/%s", this.getFirstBytePos(), this.getLastBytePos(), this.entitySize);
}
}