Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/talk/base/multipart.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 7.5 KB
Line 
1// libjingle
2// Copyright 2004--2010, Google Inc.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7//  1. Redistributions of source code must retain the above copyright notice,
8//     this list of conditions and the following disclaimer.
9//  2. Redistributions in binary form must reproduce the above copyright notice,
10//     this list of conditions and the following disclaimer in the documentation
11//     and/or other materials provided with the distribution.
12//  3. The name of the author may not be used to endorse or promote products
13//     derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
27#include "talk/base/common.h"
28#include "talk/base/httpcommon.h"
29#include "talk/base/multipart.h"
30
31namespace talk_base {
32
33///////////////////////////////////////////////////////////////////////////////
34// MultipartStream
35///////////////////////////////////////////////////////////////////////////////
36
37MultipartStream::MultipartStream(const std::string& type,
38                                 const std::string& boundary)
39    : type_(type),
40      boundary_(boundary),
41      adding_(true),
42      current_(0),
43      position_(0) {
44  // The content type should be multipart/*.
45  ASSERT(0 == strncmp(type_.c_str(), "multipart/", 10));
46}
47
48MultipartStream::~MultipartStream() {
49  Close();
50}
51
52void MultipartStream::GetContentType(std::string* content_type) {
53  ASSERT(NULL != content_type);
54  content_type->assign(type_);
55  content_type->append("; boundary=");
56  content_type->append(boundary_);
57}
58
59bool MultipartStream::AddPart(StreamInterface* data_stream,
60                              const std::string& content_disposition,
61                              const std::string& content_type) {
62  if (!AddPart("", content_disposition, content_type))
63    return false;
64  parts_.push_back(data_stream);
65  data_stream->SignalEvent.connect(this, &MultipartStream::OnEvent);
66  return true;
67}
68
69bool MultipartStream::AddPart(const std::string& data,
70                              const std::string& content_disposition,
71                              const std::string& content_type) {
72  ASSERT(adding_);
73  if (!adding_)
74    return false;
75  std::stringstream ss;
76  if (!parts_.empty()) {
77    ss << "\r\n";
78  }
79  ss << "--" << boundary_ << "\r\n";
80  if (!content_disposition.empty()) {
81    ss << ToString(HH_CONTENT_DISPOSITION) << ": "
82       << content_disposition << "\r\n";
83  }
84  if (!content_type.empty()) {
85    ss << ToString(HH_CONTENT_TYPE) << ": "
86       << content_type << "\r\n";
87  }
88  ss << "\r\n" << data;
89  parts_.push_back(new MemoryStream(ss.str().data(), ss.str().size()));
90  return true;
91}
92
93void MultipartStream::EndParts() {
94  ASSERT(adding_);
95  if (!adding_)
96    return;
97
98  std::stringstream ss;
99  if (!parts_.empty()) {
100    ss << "\r\n";
101  }
102  ss << "--" << boundary_ << "--" << "\r\n";
103  parts_.push_back(new MemoryStream(ss.str().data(), ss.str().size()));
104
105  ASSERT(0 == current_);
106  ASSERT(0 == position_);
107  adding_ = false;
108  SignalEvent(this, SE_OPEN | SE_READ, 0);
109}
110
111size_t MultipartStream::GetPartSize(const std::string& data,
112                                    const std::string& content_disposition,
113                                    const std::string& content_type) const {
114  size_t size = 0;
115  if (!parts_.empty()) {
116    size += 2;  // for "\r\n";
117  }
118  size += boundary_.size() + 4;  // for "--boundary_\r\n";
119  if (!content_disposition.empty()) {
120    // for ToString(HH_CONTENT_DISPOSITION): content_disposition\r\n
121    size += std::string(ToString(HH_CONTENT_DISPOSITION)).size() + 2 +
122        content_disposition.size() + 2;
123  }
124  if (!content_type.empty()) {
125    // for ToString(HH_CONTENT_TYPE): content_type\r\n
126    size += std::string(ToString(HH_CONTENT_TYPE)).size() + 2 +
127        content_type.size() + 2;
128  }
129  size += 2 + data.size();  // for \r\ndata
130  return size;
131}
132
133size_t MultipartStream::GetEndPartSize() const {
134  size_t size = 0;
135  if (!parts_.empty()) {
136    size += 2;  // for "\r\n";
137  }
138  size += boundary_.size() + 6;  // for "--boundary_--\r\n";
139  return size;
140}
141
142//
143// StreamInterface
144//
145
146StreamState MultipartStream::GetState() const {
147  if (adding_) {
148    return SS_OPENING;
149  }
150  return (current_ < parts_.size()) ? SS_OPEN : SS_CLOSED;
151}
152
153StreamResult MultipartStream::Read(void* buffer, size_t buffer_len,
154                                   size_t* read, int* error) {
155  if (adding_) {
156    return SR_BLOCK;
157  }
158  size_t local_read;
159  if (!read) read = &local_read;
160  while (current_ < parts_.size()) {
161    StreamResult result = parts_[current_]->Read(buffer, buffer_len, read,
162                                                 error);
163    if (SR_EOS != result) {
164      if (SR_SUCCESS == result) {
165        position_ += *read;
166      }
167      return result;
168    }
169    ++current_;
170  }
171  return SR_EOS;
172}
173
174StreamResult MultipartStream::Write(const void* data, size_t data_len,
175                                    size_t* written, int* error) {
176  if (error) {
177    *error = -1;
178  }
179  return SR_ERROR;
180}
181
182void MultipartStream::Close() {
183  for (size_t i = 0; i < parts_.size(); ++i) {
184    delete parts_[i];
185  }
186  parts_.clear();
187  adding_ = false;
188  current_ = 0;
189  position_ = 0;
190}
191
192bool MultipartStream::SetPosition(size_t position) {
193  if (adding_) {
194    return false;
195  }
196  size_t part_size, part_offset = 0;
197  for (size_t i = 0; i < parts_.size(); ++i) {
198    if (!parts_[i]->GetSize(&part_size)) {
199      return false;
200    }
201    if (part_offset + part_size > position) {
202      for (size_t j = i+1; j < _min(parts_.size(), current_+1); ++j) {
203        if (!parts_[j]->Rewind()) {
204          return false;
205        }
206      }
207      if (!parts_[i]->SetPosition(position - part_offset)) {
208        return false;
209      }
210      current_ = i;
211      position_ = position;
212      return true;
213    }
214    part_offset += part_size;
215  }
216  return false;
217}
218
219bool MultipartStream::GetPosition(size_t* position) const {
220  if (position) {
221    *position = position_;
222  }
223  return true;
224}
225
226bool MultipartStream::GetSize(size_t* size) const {
227  size_t part_size, total_size = 0;
228  for (size_t i = 0; i < parts_.size(); ++i) {
229    if (!parts_[i]->GetSize(&part_size)) {
230      return false;
231    }
232    total_size += part_size;
233  }
234  if (size) {
235    *size = total_size;
236  }
237  return true;
238}
239
240bool MultipartStream::GetAvailable(size_t* size) const {
241  if (adding_) {
242    return false;
243  }
244  size_t part_size, total_size = 0;
245  for (size_t i = current_; i < parts_.size(); ++i) {
246    if (!parts_[i]->GetAvailable(&part_size)) {
247      return false;
248    }
249    total_size += part_size;
250  }
251  if (size) {
252    *size = total_size;
253  }
254  return true;
255}
256
257//
258// StreamInterface Slots
259//
260
261void MultipartStream::OnEvent(StreamInterface* stream, int events, int error) {
262  if (adding_ || (current_ >= parts_.size()) || (parts_[current_] != stream)) {
263    return;
264  }
265  SignalEvent(this, events, error);
266}
267
268}  // namespace talk_base
Note: See TracBrowser for help on using the repository browser.