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 |