Coverage Report

Created: 2026-04-01 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/MultipartMixedContents.cxx
Line
Count
Source
1
#if defined(HAVE_CONFIG_H)
2
#include "config.h"
3
#endif
4
5
#include "resip/stack/MultipartMixedContents.hxx"
6
#include "resip/stack/SipMessage.hxx"
7
#include "rutil/Logger.hxx"
8
#include "rutil/Random.hxx"
9
#include "rutil/BaseException.hxx"
10
#include "rutil/ParseBuffer.hxx"
11
#include "rutil/WinLeakCheck.hxx"
12
13
using namespace resip;
14
using namespace std;
15
16
#define RESIPROCATE_SUBSYSTEM Subsystem::CONTENTS
17
18
bool 
19
MultipartMixedContents::init()
20
10
{
21
10
   static ContentsFactory<MultipartMixedContents> factory;
22
10
   (void)factory;
23
10
   return true;
24
10
}
25
26
MultipartMixedContents::MultipartMixedContents()
27
0
   : Contents(getStaticType()),
28
0
     mContents()
29
0
{
30
0
   setBoundary();
31
0
}
32
33
MultipartMixedContents::MultipartMixedContents(const Mime& contentsType)
34
0
   : Contents(contentsType),
35
0
     mContents()
36
0
{
37
0
   if (!mType.exists(p_boundary))
38
0
   {
39
0
      setBoundary();
40
0
   }
41
0
}
42
43
MultipartMixedContents::MultipartMixedContents(const HeaderFieldValue& hfv, const Mime& contentsType)
44
6.42k
   : Contents(hfv, contentsType),
45
6.42k
     mContents()
46
6.42k
{
47
6.42k
   if (!mType.exists(p_boundary))
48
6.42k
   {
49
6.42k
      setBoundary();
50
6.42k
   }
51
6.42k
}
52
53
MultipartMixedContents::MultipartMixedContents(const MultipartMixedContents& rhs)
54
0
   : Contents(rhs),
55
0
     mContents()
56
0
{
57
0
   vector<Contents*>::const_iterator j;
58
59
   // .bwc. Don't trigger a parse of the original by calling parts()
60
0
   const vector<Contents*>& list = rhs.mContents;
61
   
62
0
   for ( j = list.begin(); 
63
0
         j != list.end(); ++j)
64
0
   {
65
0
      resip_assert( *j );
66
0
      mContents.push_back( (*j)->clone() );
67
0
   }
68
0
}
69
70
void
71
MultipartMixedContents::setBoundary()
72
6.42k
{
73
6.42k
   Data boundaryToken = Random::getRandomHex(8);
74
6.42k
   mType.param(p_boundary) = boundaryToken;
75
6.42k
}
76
77
void
78
MultipartMixedContents::setBoundary(const Data& boundary)
79
0
{
80
0
    mType.param(p_boundary) = boundary;
81
0
}
82
83
void
84
MultipartMixedContents::clear()
85
6.42k
{
86
6.42k
   for (vector<Contents*>::iterator i = mContents.begin(); 
87
6.42k
        i != mContents.end(); ++i)
88
0
   {
89
0
      delete *i;
90
0
   }
91
6.42k
}
92
93
MultipartMixedContents::~MultipartMixedContents()
94
6.42k
{
95
6.42k
   clear();
96
6.42k
}
97
98
MultipartMixedContents&
99
MultipartMixedContents::operator=(const MultipartMixedContents& rhs)
100
0
{
101
0
   if (this != &rhs)
102
0
   {
103
0
      Contents::operator=(rhs);
104
0
      clear();
105
      
106
0
      for (vector<Contents*>::const_iterator i = rhs.mContents.begin(); 
107
0
           i != rhs.mContents.end(); ++i)
108
0
      {
109
0
         mContents.push_back( (*i)->clone() );
110
0
      }
111
0
   }
112
0
   return *this;
113
0
}
114
115
Contents* 
116
MultipartMixedContents::clone() const
117
0
{
118
0
   return new MultipartMixedContents(*this);
119
0
}
120
121
const Mime& 
122
MultipartMixedContents::getStaticType() 
123
2
{
124
2
   static Mime type("multipart","mixed");
125
2
   return type;
126
2
}
127
128
EncodeStream& 
129
MultipartMixedContents::encodeParsed(EncodeStream& str) const
130
0
{
131
0
   const Data& boundaryToken = mType.param(p_boundary);
132
0
   Data boundary(boundaryToken.size() + 2, Data::Preallocate);
133
0
   boundary = Symbols::DASHDASH;
134
0
   boundary += boundaryToken;
135
0
   boundary.replace("\"", ""); // remove quotes
136
137
0
   resip_assert( mContents.size() > 0 );
138
   
139
0
   bool first = true;
140
0
   for (vector<Contents*>::const_iterator i = mContents.begin(); 
141
0
        i != mContents.end(); ++i)
142
0
   {
143
0
      if (!first)
144
0
      {
145
0
         str << Symbols::CRLF;
146
0
      }
147
0
      else
148
0
      {
149
0
         first = false;
150
0
      }
151
0
      str << boundary << Symbols::CRLF;
152
0
      (*i)->encodeHeaders(str);
153
0
      (*i)->encode(str);
154
0
   }
155
156
   // Note:  last CRLF isn't strictly required by RFC2046 ABNF, but some implementations seem to require it so we include it
157
0
   str << Symbols::CRLF << boundary << Symbols::DASHDASH << Symbols::CRLF;
158
0
   return str;
159
0
}
160
161
// The boundary delimiter MUST occur at the beginning of a line, i.e., following
162
// a CRLF, and the initial CRLF is considered to be attached to the boundary
163
// delimiter line rather than part of the preceding part.
164
void 
165
MultipartMixedContents::parse(ParseBuffer& pb)
166
6.42k
{
167
6.42k
   const Data& boundaryToken = mType.param(p_boundary);
168
   
169
6.42k
   Data boundary(boundaryToken.size() + 4, Data::Preallocate);
170
6.42k
   boundary += Symbols::CRLF;
171
6.42k
   boundary += Symbols::DASHDASH;
172
6.42k
   boundary += boundaryToken;
173
174
6.42k
   Data boundaryNoCRLF(boundaryToken.size() + 2, Data::Preallocate);
175
6.42k
   boundaryNoCRLF += Symbols::DASHDASH;
176
6.42k
   boundaryNoCRLF += boundaryToken;
177
178
6.42k
   pb.skipToChars(boundaryNoCRLF);
179
6.42k
   pb.skipN(boundaryNoCRLF.size());
180
6.42k
   pb.assertNotEof();
181
182
6.42k
   do
183
6.42k
   {
184
      // skip over boundary
185
 
186
6.42k
      if( pb.eof() || *pb.position() != Symbols::CR[0] )
187
0
      {
188
0
         throw Exception("Invalid line ending, missing CR",__FILE__,__LINE__);
189
0
      }
190
6.42k
      pb.skipChar();
191
6.42k
      if( pb.eof() || *pb.position() != Symbols::LF[0] )
192
0
      {
193
0
         throw Exception("Invalid line ending, missing LF",__FILE__,__LINE__);
194
0
      }
195
6.42k
      pb.skipChar();
196
      
197
6.42k
      pb.assertNotEof();
198
199
6.42k
      const char* headerStart = pb.position();
200
201
      // pull out contents type only
202
6.42k
      pb.skipToChars("Content-Type");
203
6.42k
      if (pb.eof())
204
0
      {
205
0
         pb.reset(headerStart);
206
0
         pb.skipToChars("CONTENT-TYPE");
207
0
      }
208
6.42k
      pb.assertNotEof();
209
210
6.42k
      pb.skipToChar(Symbols::COLON[0]);
211
6.42k
      pb.skipChar();
212
6.42k
      pb.assertNotEof();
213
      
214
6.42k
      pb.skipWhitespace();
215
6.42k
      const char* typeStart = pb.position();
216
6.42k
      pb.assertNotEof();
217
      
218
      // determine contents-type header buffer
219
6.42k
      pb.skipToTermCRLF();
220
6.42k
      pb.assertNotEof();
221
222
6.42k
      ParseBuffer subPb(typeStart, pb.position() - typeStart);
223
6.42k
      Mime contentType;
224
6.42k
      contentType.parse(subPb);
225
      
226
6.42k
      pb.assertNotEof();
227
228
      // determine body start
229
6.42k
      pb.reset(typeStart);
230
6.42k
      const char* bodyStart = pb.skipToChars(Symbols::CRLFCRLF);
231
6.42k
      pb.assertNotEof();
232
6.42k
      bodyStart += 4;
233
234
      // determine contents body buffer
235
6.42k
      pb.skipToChars(boundary);
236
6.42k
      pb.assertNotEof();
237
6.42k
      Data tmp;
238
6.42k
      pb.data(tmp, bodyStart);
239
      // create contents against body
240
6.42k
      mContents.push_back(createContents(contentType, tmp));
241
      // pre-parse headers
242
6.42k
      ParseBuffer headersPb(headerStart, bodyStart-4-headerStart);
243
6.42k
      mContents.back()->preParseHeaders(headersPb);
244
245
6.42k
      pb.skipN(boundary.size());
246
247
6.42k
      const char* loc = pb.position();
248
6.42k
      pb.skipChar();
249
6.42k
      pb.skipChar();
250
6.42k
      Data next;
251
6.42k
      pb.data(next, loc);
252
253
6.42k
      if ( next == Symbols::DASHDASH )
254
0
      {
255
0
         break;
256
0
      }
257
6.42k
      pb.reset( loc );
258
6.42k
   }
259
6.42k
   while ( !pb.eof() );
260
261
6.42k
}
262
263
/* ====================================================================
264
 * The Vovida Software License, Version 1.0 
265
 * 
266
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
267
 * 
268
 * Redistribution and use in source and binary forms, with or without
269
 * modification, are permitted provided that the following conditions
270
 * are met:
271
 * 
272
 * 1. Redistributions of source code must retain the above copyright
273
 *    notice, this list of conditions and the following disclaimer.
274
 * 
275
 * 2. Redistributions in binary form must reproduce the above copyright
276
 *    notice, this list of conditions and the following disclaimer in
277
 *    the documentation and/or other materials provided with the
278
 *    distribution.
279
 * 
280
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
281
 *    and "Vovida Open Communication Application Library (VOCAL)" must
282
 *    not be used to endorse or promote products derived from this
283
 *    software without prior written permission. For written
284
 *    permission, please contact vocal@vovida.org.
285
 *
286
 * 4. Products derived from this software may not be called "VOCAL", nor
287
 *    may "VOCAL" appear in their name, without prior written
288
 *    permission of Vovida Networks, Inc.
289
 * 
290
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
291
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
292
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
293
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
294
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
295
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
296
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
297
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
298
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
299
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
300
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
301
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
302
 * DAMAGE.
303
 * 
304
 * ====================================================================
305
 * 
306
 * This software consists of voluntary contributions made by Vovida
307
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
308
 * Inc.  For more information on Vovida Networks, Inc., please see
309
 * <http://www.vovida.org/>.
310
 *
311
 */