• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MultipartStream(const std::string & type,const std::string & boundary)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 
~MultipartStream()33 MultipartStream::~MultipartStream() {
34   Close();
35 }
36 
GetContentType(std::string * content_type)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 
AddPart(StreamInterface * data_stream,const std::string & content_disposition,const std::string & content_type)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 
AddPart(const std::string & data,const std::string & content_disposition,const std::string & content_type)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 
EndParts()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 
GetPartSize(const std::string & data,const std::string & content_disposition,const std::string & content_type) const96 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 
GetEndPartSize() const118 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 
GetState() const131 StreamState MultipartStream::GetState() const {
132   if (adding_) {
133     return SS_OPENING;
134   }
135   return (current_ < parts_.size()) ? SS_OPEN : SS_CLOSED;
136 }
137 
Read(void * buffer,size_t buffer_len,size_t * read,int * error)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 
Write(const void * data,size_t data_len,size_t * written,int * error)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 
Close()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 
SetPosition(size_t position)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 
GetPosition(size_t * position) const204 bool MultipartStream::GetPosition(size_t* position) const {
205   if (position) {
206     *position = position_;
207   }
208   return true;
209 }
210 
GetSize(size_t * size) const211 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 
GetAvailable(size_t * size) const225 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 
OnEvent(StreamInterface * stream,int events,int error)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
254