| OLD | NEW |
| (Empty) |
| 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 #include <algorithm> | |
| 12 #include "webrtc/base/common.h" | |
| 13 #include "webrtc/base/httpcommon.h" | |
| 14 #include "webrtc/base/multipart.h" | |
| 15 | |
| 16 namespace rtc { | |
| 17 | |
| 18 /////////////////////////////////////////////////////////////////////////////// | |
| 19 // MultipartStream | |
| 20 /////////////////////////////////////////////////////////////////////////////// | |
| 21 | |
| 22 MultipartStream::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 | |
| 33 MultipartStream::~MultipartStream() { | |
| 34 Close(); | |
| 35 } | |
| 36 | |
| 37 void 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 | |
| 44 bool 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 | |
| 54 bool 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 | |
| 78 void 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 | |
| 96 size_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 | |
| 118 size_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 | |
| 131 StreamState MultipartStream::GetState() const { | |
| 132 if (adding_) { | |
| 133 return SS_OPENING; | |
| 134 } | |
| 135 return (current_ < parts_.size()) ? SS_OPEN : SS_CLOSED; | |
| 136 } | |
| 137 | |
| 138 StreamResult 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 | |
| 159 StreamResult 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 | |
| 167 void 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 | |
| 177 bool 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 < std::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 | |
| 204 bool MultipartStream::GetPosition(size_t* position) const { | |
| 205 if (position) { | |
| 206 *position = position_; | |
| 207 } | |
| 208 return true; | |
| 209 } | |
| 210 | |
| 211 bool 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 | |
| 225 bool 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 | |
| 246 void 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 | |
| OLD | NEW |