summaryrefslogtreecommitdiffstats
path: root/net/base/upload_data.cc
blob: 198b051fd9d4942cd310bb003e7160500dbbeb86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/base/upload_data.h"

#include "base/file_util.h"
#include "base/logging.h"
#include "net/base/net_errors.h"

namespace net {

uint64 UploadData::GetContentLength() {
  uint64 len = 0;
  std::vector<Element>::iterator it = elements_.begin();
  for (; it != elements_.end(); ++it)
    len += (*it).GetContentLength();
  return len;
}

uint64 UploadData::Element::GetContentLength() {
  if (override_content_length_ || content_length_computed_)
    return content_length_;

  if (type_ == TYPE_BYTES)
    return static_cast<uint64>(bytes_.size());

  DCHECK_EQ(TYPE_FILE, type_);
  DCHECK(!file_stream_);

  // TODO(darin): This size calculation could be out of sync with the state of
  // the file when we get around to reading it.  We should probably find a way
  // to lock the file or somehow protect against this error condition.

  content_length_computed_ = true;
  content_length_ = 0;

  // We need to open the file here to decide if we should report the file's
  // size or zero.  We cache the open file, so that we can still read it when
  // it comes time to.
  file_stream_ = NewFileStreamForReading();
  if (!file_stream_)
    return 0;

  int64 length = 0;
  if (!file_util::GetFileSize(file_path_, &length))
    return 0;

  if (file_range_offset_ >= static_cast<uint64>(length))
    return 0;  // range is beyond eof

  // compensate for the offset and clip file_range_length_ to eof
  content_length_ =  std::min(length - file_range_offset_, file_range_length_);
  return content_length_;
}

FileStream* UploadData::Element::NewFileStreamForReading() {
  // In common usage GetContentLength() will call this first and store the
  // result into |file_| and a subsequent call (from UploadDataStream) will
  // get the cached open FileStream.
  if (file_stream_) {
    FileStream* file = file_stream_;
    file_stream_ = NULL;
    return file;
  }

  scoped_ptr<FileStream> file(new FileStream());
  int64 rv = file->Open(file_path_,
                      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ);
  if (rv != OK) {
    // If the file can't be opened, we'll just upload an empty file.
    DLOG(WARNING) << "Failed to open \"" << file_path_.value()
                  << "\" for reading: " << rv;
    return NULL;
  }
  if (file_range_offset_) {
    rv = file->Seek(FROM_BEGIN, file_range_offset_);
    if (rv < 0) {
      DLOG(WARNING) << "Failed to seek \"" << file_path_.value()
                    << "\" to offset: " << file_range_offset_ << " (" << rv
                    << ")";
      return NULL;
    }
  }

  return file.release();
}

}  // namespace net