Home | History | Annotate | Download | only in base
      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
    254