1/* 2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 12#include "webrtc/base/common.h" 13#include "webrtc/base/httpcommon.h" 14#include "webrtc/base/multipart.h" 15 16namespace rtc { 17 18/////////////////////////////////////////////////////////////////////////////// 19// MultipartStream 20/////////////////////////////////////////////////////////////////////////////// 21 22MultipartStream::MultipartStream(const std::string& type, 23 const std::string& boundary) 24 : type_(type), 25 boundary_(boundary), 26 adding_(true), 27 current_(0), 28 position_(0) { 29 // The content type should be multipart/*. 30 ASSERT(0 == strncmp(type_.c_str(), "multipart/", 10)); 31} 32 33MultipartStream::~MultipartStream() { 34 Close(); 35} 36 37void MultipartStream::GetContentType(std::string* content_type) { 38 ASSERT(NULL != content_type); 39 content_type->assign(type_); 40 content_type->append("; boundary="); 41 content_type->append(boundary_); 42} 43 44bool MultipartStream::AddPart(StreamInterface* data_stream, 45 const std::string& content_disposition, 46 const std::string& content_type) { 47 if (!AddPart("", content_disposition, content_type)) 48 return false; 49 parts_.push_back(data_stream); 50 data_stream->SignalEvent.connect(this, &MultipartStream::OnEvent); 51 return true; 52} 53 54bool MultipartStream::AddPart(const std::string& data, 55 const std::string& content_disposition, 56 const std::string& content_type) { 57 ASSERT(adding_); 58 if (!adding_) 59 return false; 60 std::stringstream ss; 61 if (!parts_.empty()) { 62 ss << "\r\n"; 63 } 64 ss << "--" << boundary_ << "\r\n"; 65 if (!content_disposition.empty()) { 66 ss << ToString(HH_CONTENT_DISPOSITION) << ": " 67 << content_disposition << "\r\n"; 68 } 69 if (!content_type.empty()) { 70 ss << ToString(HH_CONTENT_TYPE) << ": " 71 << content_type << "\r\n"; 72 } 73 ss << "\r\n" << data; 74 parts_.push_back(new MemoryStream(ss.str().data(), ss.str().size())); 75 return true; 76} 77 78void MultipartStream::EndParts() { 79 ASSERT(adding_); 80 if (!adding_) 81 return; 82 83 std::stringstream ss; 84 if (!parts_.empty()) { 85 ss << "\r\n"; 86 } 87 ss << "--" << boundary_ << "--" << "\r\n"; 88 parts_.push_back(new MemoryStream(ss.str().data(), ss.str().size())); 89 90 ASSERT(0 == current_); 91 ASSERT(0 == position_); 92 adding_ = false; 93 SignalEvent(this, SE_OPEN | SE_READ, 0); 94} 95 96size_t MultipartStream::GetPartSize(const std::string& data, 97 const std::string& content_disposition, 98 const std::string& content_type) const { 99 size_t size = 0; 100 if (!parts_.empty()) { 101 size += 2; // for "\r\n"; 102 } 103 size += boundary_.size() + 4; // for "--boundary_\r\n"; 104 if (!content_disposition.empty()) { 105 // for ToString(HH_CONTENT_DISPOSITION): content_disposition\r\n 106 size += std::string(ToString(HH_CONTENT_DISPOSITION)).size() + 2 + 107 content_disposition.size() + 2; 108 } 109 if (!content_type.empty()) { 110 // for ToString(HH_CONTENT_TYPE): content_type\r\n 111 size += std::string(ToString(HH_CONTENT_TYPE)).size() + 2 + 112 content_type.size() + 2; 113 } 114 size += 2 + data.size(); // for \r\ndata 115 return size; 116} 117 118size_t MultipartStream::GetEndPartSize() const { 119 size_t size = 0; 120 if (!parts_.empty()) { 121 size += 2; // for "\r\n"; 122 } 123 size += boundary_.size() + 6; // for "--boundary_--\r\n"; 124 return size; 125} 126 127// 128// StreamInterface 129// 130 131StreamState MultipartStream::GetState() const { 132 if (adding_) { 133 return SS_OPENING; 134 } 135 return (current_ < parts_.size()) ? SS_OPEN : SS_CLOSED; 136} 137 138StreamResult MultipartStream::Read(void* buffer, size_t buffer_len, 139 size_t* read, int* error) { 140 if (adding_) { 141 return SR_BLOCK; 142 } 143 size_t local_read; 144 if (!read) read = &local_read; 145 while (current_ < parts_.size()) { 146 StreamResult result = parts_[current_]->Read(buffer, buffer_len, read, 147 error); 148 if (SR_EOS != result) { 149 if (SR_SUCCESS == result) { 150 position_ += *read; 151 } 152 return result; 153 } 154 ++current_; 155 } 156 return SR_EOS; 157} 158 159StreamResult MultipartStream::Write(const void* data, size_t data_len, 160 size_t* written, int* error) { 161 if (error) { 162 *error = -1; 163 } 164 return SR_ERROR; 165} 166 167void MultipartStream::Close() { 168 for (size_t i = 0; i < parts_.size(); ++i) { 169 delete parts_[i]; 170 } 171 parts_.clear(); 172 adding_ = false; 173 current_ = 0; 174 position_ = 0; 175} 176 177bool MultipartStream::SetPosition(size_t position) { 178 if (adding_) { 179 return false; 180 } 181 size_t part_size, part_offset = 0; 182 for (size_t i = 0; i < parts_.size(); ++i) { 183 if (!parts_[i]->GetSize(&part_size)) { 184 return false; 185 } 186 if (part_offset + part_size > position) { 187 for (size_t j = i+1; j < _min(parts_.size(), current_+1); ++j) { 188 if (!parts_[j]->Rewind()) { 189 return false; 190 } 191 } 192 if (!parts_[i]->SetPosition(position - part_offset)) { 193 return false; 194 } 195 current_ = i; 196 position_ = position; 197 return true; 198 } 199 part_offset += part_size; 200 } 201 return false; 202} 203 204bool MultipartStream::GetPosition(size_t* position) const { 205 if (position) { 206 *position = position_; 207 } 208 return true; 209} 210 211bool MultipartStream::GetSize(size_t* size) const { 212 size_t part_size, total_size = 0; 213 for (size_t i = 0; i < parts_.size(); ++i) { 214 if (!parts_[i]->GetSize(&part_size)) { 215 return false; 216 } 217 total_size += part_size; 218 } 219 if (size) { 220 *size = total_size; 221 } 222 return true; 223} 224 225bool MultipartStream::GetAvailable(size_t* size) const { 226 if (adding_) { 227 return false; 228 } 229 size_t part_size, total_size = 0; 230 for (size_t i = current_; i < parts_.size(); ++i) { 231 if (!parts_[i]->GetAvailable(&part_size)) { 232 return false; 233 } 234 total_size += part_size; 235 } 236 if (size) { 237 *size = total_size; 238 } 239 return true; 240} 241 242// 243// StreamInterface Slots 244// 245 246void MultipartStream::OnEvent(StreamInterface* stream, int events, int error) { 247 if (adding_ || (current_ >= parts_.size()) || (parts_[current_] != stream)) { 248 return; 249 } 250 SignalEvent(this, events, error); 251} 252 253} // namespace rtc 254