Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/streamconv/converters/nsMultiMixedConv.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
#ifndef __nsmultimixedconv__h__
6
#define __nsmultimixedconv__h__
7
8
#include "nsIStreamConverter.h"
9
#include "nsIChannel.h"
10
#include "nsString.h"
11
#include "nsCOMPtr.h"
12
#include "nsIByteRangeRequest.h"
13
#include "nsILoadInfo.h"
14
#include "nsIMultiPartChannel.h"
15
#include "nsAutoPtr.h"
16
#include "mozilla/Attributes.h"
17
#include "mozilla/IncrementalTokenizer.h"
18
#include "nsHttpResponseHead.h"
19
20
#define NS_MULTIMIXEDCONVERTER_CID                         \
21
{ /* 7584CE90-5B25-11d3-A175-0050041CAF44 */         \
22
    0x7584ce90,                                      \
23
    0x5b25,                                          \
24
    0x11d3,                                          \
25
    {0xa1, 0x75, 0x0, 0x50, 0x4, 0x1c, 0xaf, 0x44}       \
26
}
27
28
//
29
// nsPartChannel is a "dummy" channel which represents an individual part of
30
// a multipart/mixed stream...
31
//
32
// Instances on this channel are passed out to the consumer through the
33
// nsIStreamListener interface.
34
//
35
class nsPartChannel final : public nsIChannel,
36
                            public nsIByteRangeRequest,
37
                            public nsIMultiPartChannel
38
{
39
public:
40
  nsPartChannel(nsIChannel *aMultipartChannel, uint32_t aPartID,
41
                nsIStreamListener* aListener);
42
43
  void InitializeByteRange(int64_t aStart, int64_t aEnd);
44
0
  void SetIsLastPart() { mIsLastPart = true; }
45
  nsresult SendOnStartRequest(nsISupports* aContext);
46
  nsresult SendOnDataAvailable(nsISupports* aContext, nsIInputStream* aStream,
47
                               uint64_t aOffset, uint32_t aLen);
48
  nsresult SendOnStopRequest(nsISupports* aContext, nsresult aStatus);
49
  /* SetContentDisposition expects the full value of the Content-Disposition
50
   * header */
51
  void SetContentDisposition(const nsACString& aContentDispositionHeader);
52
0
  void SetResponseHead(mozilla::net::nsHttpResponseHead * head) { mResponseHead = head; }
53
54
  NS_DECL_ISUPPORTS
55
  NS_DECL_NSIREQUEST
56
  NS_DECL_NSICHANNEL
57
  NS_DECL_NSIBYTERANGEREQUEST
58
  NS_DECL_NSIMULTIPARTCHANNEL
59
60
protected:
61
0
  ~nsPartChannel() = default;
62
63
protected:
64
  nsCOMPtr<nsIChannel>    mMultipartChannel;
65
  nsCOMPtr<nsIStreamListener> mListener;
66
  nsAutoPtr<mozilla::net::nsHttpResponseHead> mResponseHead;
67
68
  nsresult                mStatus;
69
  nsLoadFlags             mLoadFlags;
70
71
  nsCOMPtr<nsILoadGroup>  mLoadGroup;
72
73
  nsCString               mContentType;
74
  nsCString               mContentCharset;
75
  uint32_t                mContentDisposition;
76
  nsString                mContentDispositionFilename;
77
  nsCString               mContentDispositionHeader;
78
  uint64_t                mContentLength;
79
80
  bool                    mIsByteRangeRequest;
81
  int64_t                 mByteRangeStart;
82
  int64_t                 mByteRangeEnd;
83
84
  uint32_t                mPartID; // unique ID that can be used to identify
85
                                   // this part of the multipart document
86
  bool                    mIsLastPart;
87
};
88
89
// The nsMultiMixedConv stream converter converts a stream of type "multipart/x-mixed-replace"
90
// to it's subparts. There was some debate as to whether or not the functionality desired
91
// when HTTP confronted this type required a stream converter. After all, this type really
92
// prompts various viewer related actions rather than stream conversion. There simply needs
93
// to be a piece in place that can strip out the multiple parts of a stream of this type, and
94
// "display" them accordingly.
95
//
96
// With that said, this "stream converter" spends more time packaging up the sub parts of the
97
// main stream and sending them off the destination stream listener, than doing any real
98
// stream parsing/converting.
99
//
100
// WARNING: This converter requires that it's destination stream listener be able to handle
101
//   multiple OnStartRequest(), OnDataAvailable(), and OnStopRequest() call combinations.
102
//   Each series represents the beginning, data production, and ending phase of each sub-
103
//   part of the original stream.
104
//
105
// NOTE: this MIME-type is used by HTTP, *not* SMTP, or IMAP.
106
//
107
// NOTE: For reference, a general description of how this MIME type should be handled via
108
//   HTTP, see http://home.netscape.com/assist/net_sites/pushpull.html . Note that
109
//   real world server content deviates considerably from this overview.
110
//
111
// Implementation assumptions:
112
//  Assumed structue:
113
//  --BoundaryToken[\r]\n
114
//  content-type: foo/bar[\r]\n
115
//  ... (other headers if any)
116
//  [\r]\n (second line feed to delimit end of headers)
117
//  data
118
//  --BoundaryToken-- (end delimited by final "--")
119
//
120
// linebreaks can be either CRLF or LFLF. linebreaks preceding
121
// boundary tokens are NOT considered part of the data. BoundaryToken
122
// is any opaque string.
123
//
124
//
125
126
class nsMultiMixedConv : public nsIStreamConverter {
127
public:
128
    NS_DECL_ISUPPORTS
129
    NS_DECL_NSISTREAMCONVERTER
130
    NS_DECL_NSISTREAMLISTENER
131
    NS_DECL_NSIREQUESTOBSERVER
132
133
    explicit nsMultiMixedConv();
134
135
protected:
136
    typedef mozilla::IncrementalTokenizer::Token Token;
137
138
0
    virtual ~nsMultiMixedConv() = default;
139
140
    nsresult SendStart();
141
    void AccumulateData(Token const & aToken);
142
    nsresult SendData();
143
    nsresult SendStop(nsresult aStatus);
144
145
    // member data
146
    nsCOMPtr<nsIStreamListener> mFinalListener; // this guy gets the converted data via his OnDataAvailable()
147
148
    nsCOMPtr<nsIChannel> mChannel; // The channel as we get in in OnStartRequest call
149
    RefPtr<nsPartChannel> mPartChannel;   // the channel for the given part we're processing.
150
                                        // one channel per part.
151
    nsCOMPtr<nsISupports> mContext;
152
    nsCString           mContentType;
153
    nsCString           mContentDisposition;
154
    nsCString           mContentSecurityPolicy;
155
    nsCString           mRootContentSecurityPolicy;
156
    uint64_t            mContentLength;
157
    uint64_t            mTotalSent;
158
159
    // The following members are for tracking the byte ranges in
160
    // multipart/mixed content which specified the 'Content-Range:'
161
    // header...
162
    int64_t             mByteRangeStart;
163
    int64_t             mByteRangeEnd;
164
    bool                mIsByteRangeRequest;
165
    // This flag is set first time we create a part channel.
166
    // We use it to prevent duplicated OnStopRequest call on the listener
167
    // when we fail from some reason to ever create a part channel that
168
    // ensures correct notifications.
169
    bool                mRequestListenerNotified;
170
171
    uint32_t            mCurrentPartID;
172
173
    // Flag preventing reenter of OnDataAvailable in case the target listener
174
    // ends up spinning the event loop.
175
    bool                mInOnDataAvailable;
176
177
    // Current state of the incremental parser
178
    enum EParserState {
179
      PREAMBLE,
180
      BOUNDARY_CRLF,
181
      HEADER_NAME,
182
      HEADER_SEP,
183
      HEADER_VALUE,
184
      BODY_INIT,
185
      BODY,
186
      TRAIL_DASH1,
187
      TRAIL_DASH2,
188
      EPILOGUE,
189
190
      INIT = PREAMBLE
191
    } mParserState;
192
193
    // Response part header value, valid when we find a header name
194
    // we recognize.
195
    enum EHeader : uint32_t {
196
      HEADER_FIRST,
197
      HEADER_CONTENT_TYPE = HEADER_FIRST,
198
      HEADER_CONTENT_LENGTH,
199
      HEADER_CONTENT_DISPOSITION,
200
      HEADER_SET_COOKIE,
201
      HEADER_CONTENT_RANGE,
202
      HEADER_RANGE,
203
      HEADER_CONTENT_SECURITY_POLICY,
204
      HEADER_UNKNOWN
205
    } mResponseHeader;
206
    // Cumulated value of a response header.
207
    nsCString mResponseHeaderValue;
208
209
    nsCString mBoundary;
210
    mozilla::IncrementalTokenizer mTokenizer;
211
212
    // When in the "body parsing" mode, see below, we cumulate raw data
213
    // incrementally to mainly avoid any unnecessary granularity.
214
    // mRawData points to the first byte in the tokenizer buffer where part
215
    // body data begins or continues.  mRawDataLength is a cumulated length
216
    // of that data during a single tokenizer input feed.  This is always
217
    // flushed right after we fed the tokenizer.
218
    nsACString::const_char_iterator mRawData;
219
    nsACString::size_type mRawDataLength;
220
221
    // At the start we don't know if the server will be sending boundary with
222
    // or without the leading dashes.
223
    Token mBoundaryToken;
224
    Token mBoundaryTokenWithDashes;
225
    // We need these custom tokens to allow finding CRLF when in the binary mode.
226
    // CRLF before boundary is considered part of the boundary and not part of
227
    // the data.
228
    Token mLFToken;
229
    Token mCRLFToken;
230
    // Custom tokens for each of the response headers we recognize.
231
    Token mHeaderTokens[HEADER_UNKNOWN];
232
233
    // Resets values driven by part headers, like content type, to their defaults,
234
    // called at the start of every part processing.
235
    void HeadersToDefault();
236
    // Processes captured value of mResponseHeader header.
237
    nsresult ProcessHeader();
238
    // Switches the parser and tokenizer state to "binary mode" which only searches
239
    // for the 'CRLF boundary' delimiter.
240
    void SwitchToBodyParsing();
241
    // Switches to the default mode, we are in this mode when parsing headers and
242
    // control data around the boundary delimiters.
243
    void SwitchToControlParsing();
244
    // Turns on or off recognition of the headers we recognize in part heads.
245
    void SetHeaderTokensEnabled(bool aEnable);
246
247
    // The main parser callback called by the IncrementalTokenizer
248
    // instance from OnDataAvailable or OnStopRequest.
249
    nsresult ConsumeToken(Token const & token);
250
};
251
252
#endif /* __nsmultimixedconv__h__ */