1// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <algorithm>
6
7#include "base/format_macros.h"
8#include "base/logging.h"
9#include "base/strings/stringprintf.h"
10#include "net/http/http_byte_range.h"
11
12namespace {
13
14const int64 kPositionNotSpecified = -1;
15
16}  // namespace
17
18namespace net {
19
20HttpByteRange::HttpByteRange()
21    : first_byte_position_(kPositionNotSpecified),
22      last_byte_position_(kPositionNotSpecified),
23      suffix_length_(kPositionNotSpecified),
24      has_computed_bounds_(false) {
25}
26
27// static
28HttpByteRange HttpByteRange::Bounded(int64 first_byte_position,
29                                     int64 last_byte_position) {
30  HttpByteRange range;
31  range.set_first_byte_position(first_byte_position);
32  range.set_last_byte_position(last_byte_position);
33  return range;
34}
35
36// static
37HttpByteRange HttpByteRange::RightUnbounded(int64 first_byte_position) {
38  HttpByteRange range;
39  range.set_first_byte_position(first_byte_position);
40  return range;
41}
42
43// static
44HttpByteRange HttpByteRange::Suffix(int64 suffix_length) {
45  HttpByteRange range;
46  range.set_suffix_length(suffix_length);
47  return range;
48}
49
50bool HttpByteRange::IsSuffixByteRange() const {
51  return suffix_length_ != kPositionNotSpecified;
52}
53
54bool HttpByteRange::HasFirstBytePosition() const {
55  return first_byte_position_ != kPositionNotSpecified;
56}
57
58bool HttpByteRange::HasLastBytePosition() const {
59  return last_byte_position_ != kPositionNotSpecified;
60}
61
62bool HttpByteRange::IsValid() const {
63  if (suffix_length_ > 0)
64    return true;
65  return (first_byte_position_ >= 0 &&
66          (last_byte_position_ == kPositionNotSpecified ||
67           last_byte_position_ >= first_byte_position_));
68}
69
70std::string HttpByteRange::GetHeaderValue() const {
71  DCHECK(IsValid());
72
73  if (IsSuffixByteRange())
74    return base::StringPrintf("bytes=-%" PRId64, suffix_length());
75
76  DCHECK(HasFirstBytePosition());
77
78  if (!HasLastBytePosition())
79    return base::StringPrintf("bytes=%" PRId64 "-", first_byte_position());
80
81  return base::StringPrintf("bytes=%" PRId64 "-%" PRId64,
82                            first_byte_position(), last_byte_position());
83}
84
85bool HttpByteRange::ComputeBounds(int64 size) {
86  if (size < 0)
87    return false;
88  if (has_computed_bounds_)
89    return false;
90  has_computed_bounds_ = true;
91
92  // Empty values.
93  if (!HasFirstBytePosition() &&
94      !HasLastBytePosition() &&
95      !IsSuffixByteRange()) {
96    first_byte_position_ = 0;
97    last_byte_position_ = size - 1;
98    return true;
99  }
100  if (!IsValid())
101    return false;
102  if (IsSuffixByteRange()) {
103    first_byte_position_ = size - std::min(size, suffix_length_);
104    last_byte_position_ = size - 1;
105    return true;
106  }
107  if (first_byte_position_ < size) {
108    if (HasLastBytePosition())
109      last_byte_position_ = std::min(size - 1, last_byte_position_);
110    else
111      last_byte_position_ = size - 1;
112    return true;
113  }
114  return false;
115}
116
117}  // namespace net
118