|
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // |
|
15 |
|
16 #ifndef __CHTTPMESSAGECOMPOSER_H__ |
|
17 #define __CHTTPMESSAGECOMPOSER_H__ |
|
18 |
|
19 #include <e32base.h> |
|
20 #include <http/mhttpdatasupplier.h> |
|
21 |
|
22 #include "timerlogger.h" |
|
23 #include "mhttpbuffersupplier.h" |
|
24 #include "thttpdatacomposer.h" |
|
25 |
|
26 |
|
27 class MHttpMessageComposerObserver; |
|
28 |
|
29 class CHttpMessageComposer : public CActive, |
|
30 public MHttpBufferSupplier |
|
31 /** |
|
32 The CHttpMessageComposer class provides functionality for creating HTTP/1.1 |
|
33 messages as defined in RFC2616. The HTTP/1.1 protocol specifies that the CR |
|
34 LF sequence is the end of line (eol) marker for all protocol elements except |
|
35 the entity-body. |
|
36 |
|
37 The composer does not process any header fields or start-line tokens. |
|
38 Therefore it needs to be told if headers and/or an entity body is expected. |
|
39 If the message does contain an entity body and the size of the body data is |
|
40 not known then the composer will apply the chunked transfer encoding to the |
|
41 entity body. |
|
42 |
|
43 The composer needs an observer (MHttpMessageComposerObserver). The observer |
|
44 supplies the message info such as the start-line tokens, header field tokens |
|
45 and other message info. An MHTTPDataSupplier object is used to supply the |
|
46 entity body data if there is one. The observer must ensure that the |
|
47 descriptors containing the tokens it supplies remain valid until the composer |
|
48 notifies it that the message is complete. |
|
49 |
|
50 The composer is initially in the Idle state waiting to be notified of |
|
51 available message info. When it is notified, the composer moves into the |
|
52 CreatingStartLine state. |
|
53 |
|
54 In the CreatingStartLine state the composer obtains the start-line tokens |
|
55 from the observer. These are added to the current data buffer. The composer |
|
56 moves to the CreatingHeaders state. |
|
57 |
|
58 In the CreatingHeaders state the composer adds header fields to the current |
|
59 data buffer. The observer provides the header field tokens for the field |
|
60 name and field value. The composer will not fold header field values onto |
|
61 multiple lines unless the provided field token already contains folded field |
|
62 values. The observer also informs the composer if there is no more header |
|
63 field data. The composer remains in the CreatingHeaders state until there |
|
64 are no more header field values. |
|
65 |
|
66 In this case the composer adds an empty line to the current data buffer to |
|
67 mark the end of the header fields section. The current data buffer is ready |
|
68 to be sent and the composer informs its observer of this. The composer moves |
|
69 into the PendingEntityBody and waits for the observer to notify it that it |
|
70 has finished with the current data buffer. |
|
71 |
|
72 In the PendingEntityBody state the composer releases the current data buffer. |
|
73 It then asks its observer if the message has an entity body. If there is no |
|
74 entity body or if it is zero length then the composer moves to PendingIdle |
|
75 state. If there is an entity body and the size is known the composer moves |
|
76 to the SendEntityData state. If the entity body size is unknown the composer |
|
77 moves to the CreatingChunkSize state. |
|
78 |
|
79 In the SendEntityBody state the composer gets the next entity body data part |
|
80 from the data supplier for the entity body. It sets this data as the current |
|
81 send buffer and notifies the observer that message data is ready. A check is |
|
82 made to see that if the data supplier claims that this is the last data part |
|
83 that all the specified amount of entity body data has been sent. If this is |
|
84 not true the observer will receive an error code of KErrCorrupt. The composer |
|
85 moves to PendingReleaseData state and waits for the observer to notify it |
|
86 that it has finished with the current data buffer. |
|
87 |
|
88 In the PendingReleaseData state the composer notifies the entity body data |
|
89 supplier that it has finished with the current data part. If all the |
|
90 specified entity body data has been sent the composer moves to the |
|
91 PendingIdle state. If there is more entity body data to send the composer |
|
92 moves to the SendEntityData and waits for the observer to notify it that |
|
93 there is more message info available. |
|
94 |
|
95 In the CreatingChunkSize state the composer adds the size of the following |
|
96 chunk-data component to the current send buffer as defined in RFC2616 |
|
97 section 3.6.1. The send buffer wil contain the empty line delimiting the |
|
98 previous chunk-data component if this is not the first chunk-size component |
|
99 to be sent. The composer notifies its observer that message data is ready. |
|
100 The composer moves into the SendChunkData state and waits for the observer |
|
101 to notify it that it has finished with the current data buffer. |
|
102 |
|
103 If the chunk-data is zero-length then the chunk-size component is not added |
|
104 to the send buffer. |
|
105 |
|
106 In the SendChunkData state the composer releases the current data buffer. It |
|
107 then gets the chunk-data from the data supplier for the entity body. It sets |
|
108 this data as the current buffer. The observer is only notified that message |
|
109 data is ready if the chunk-data is not zer-length. The composer moves into |
|
110 the PendingReleaseChunk state and waits for the observer to notify it that |
|
111 it has finished with the current data buffer. |
|
112 |
|
113 In the PendingReleaseChunk state the composer notifies the entity body data |
|
114 supplier that it has finished with the current data part. If that was the |
|
115 last part of the entity body data the composer adds the last-chunk component |
|
116 to the current data buffer. It then asks the observer if the message has any |
|
117 trailer headers. If there are trailer headers then the composer moves to the |
|
118 CreatingTrailers state. Otherwise the composer moves to the |
|
119 CreatingEndOfTrailers state. |
|
120 |
|
121 If there is more entity body data to follow the composer moves to the |
|
122 CreatingChunkSize state and waits for the observer to notify it that there is |
|
123 more message info available. |
|
124 |
|
125 In the CreatingTrailers state the composer adds trailer header fields to the |
|
126 current data buffer. The observer provides the trailer header field tokens |
|
127 for the field name and field value. The composer will not fold header field |
|
128 values onto multiple lines unless the provided field token already contains |
|
129 folded field values. The observer also informs the composer if the provided |
|
130 field info is for the last trailer header field. The composer remains in the |
|
131 CreatingTrailers state until there are no more trailer header field values. |
|
132 |
|
133 In this case the composer adds an empty line to the current data buffer to |
|
134 mark the end of the trailer header fields section. The current data buffer |
|
135 is ready to be sent and the composer informs its observer of this. The |
|
136 composer moves into the PendingEndOfChunkedBody and waits for the observer |
|
137 to notify it that it has finished with the current data buffer. |
|
138 |
|
139 In the PendingEndOfChunkedBody the composer releases the current data buffer |
|
140 and moves into the PendingIdle state. |
|
141 |
|
142 In the PendingIdle state the composer informs its observer that the message |
|
143 is complete. The composer moves to the Idle state. |
|
144 @internalComponent |
|
145 @see MHttpMessageComposerObserver |
|
146 */ |
|
147 { |
|
148 public: // methods |
|
149 |
|
150 static CHttpMessageComposer* NewL(MHttpMessageComposerObserver& aObserver); |
|
151 virtual ~CHttpMessageComposer(); |
|
152 |
|
153 void MessageInfoAvailable(); |
|
154 void GetMessageData(TPtrC8& aData); |
|
155 void ReleaseMessageData(); |
|
156 void Reset(); |
|
157 TBool CheckMessagePendingComplete(); |
|
158 |
|
159 private: // enums |
|
160 |
|
161 enum TComposerState |
|
162 /** |
|
163 The TComposerState enumeration defines the state machine for the http message |
|
164 state machine. |
|
165 */ |
|
166 { |
|
167 /** The composer is idle. |
|
168 */ |
|
169 EIdle = 0, |
|
170 |
|
171 /** The start-line is being created. The next state depends on whether |
|
172 there are headers or not. |
|
173 */ |
|
174 ECreatingStartLine, |
|
175 |
|
176 /** The message has header fields. The next header field is added to the |
|
177 http message. The composer remains in this state until all the header |
|
178 fields have been added. If there is no more header field info an |
|
179 empty line is added. The composer has prepared the first part of the |
|
180 http message and can notify its observer that message data is ready. |
|
181 */ |
|
182 ECreatingHeaders, |
|
183 |
|
184 /** The composer needs to decide whether there is entity body and if so |
|
185 does it need to be chunk encoded or not. |
|
186 */ |
|
187 EPendingEntityBody, |
|
188 |
|
189 /** The message has a non-encoded entity body. It notifies its observer |
|
190 that message data is ready. |
|
191 */ |
|
192 ESendEntityData, |
|
193 |
|
194 /** The composer releases the current entity body data. If all the body |
|
195 data has been sent then the message is complete. Otherwise the |
|
196 composer waits to be notified that more entity body data is available. |
|
197 */ |
|
198 EPendingReleaseData, |
|
199 |
|
200 /** There is entity body to sent as in chunk-encoded format. The chunk- |
|
201 size component specifying the size of the subsequent chunk-data is |
|
202 added to the send buffer. The composer notifies its observer that it |
|
203 has message ready. Note the send buffer will contain the empty line |
|
204 marking the end of the previous chunk-data if this is not the first |
|
205 chunk-size. |
|
206 */ |
|
207 ECreatingChunkSize, |
|
208 |
|
209 /** The chunk-data is ready to be sent. The observer is notified that |
|
210 there is message data ready. |
|
211 */ |
|
212 ESendChunkData, |
|
213 |
|
214 /** The composer releases the current chunk-data. If this was the last |
|
215 chunk-data then the composer checks for trailer headers. If there |
|
216 are no trailer then the message is complete, otherwise the trailers |
|
217 are added. |
|
218 */ |
|
219 EPendingReleaseChunk, |
|
220 |
|
221 /** The message has trailer header fields. The next trailer header field |
|
222 is added to the http message. The composer remains in this state |
|
223 until all the trailer header fields have been added. If there is no |
|
224 more trailer header field info an empty line is added. The composer |
|
225 has prepared the final part of the http message and can notify its |
|
226 observer that message data is ready. |
|
227 */ |
|
228 ECreatingTrailers, |
|
229 |
|
230 /** The composer releases the current data buffer. The observer needs |
|
231 to be informed that message is complete. |
|
232 */ |
|
233 EPendingEndOfChunkedBody, |
|
234 |
|
235 /** The message is complete and the composer is waiting to go idle. The |
|
236 observer is notified. |
|
237 */ |
|
238 EPendingIdle |
|
239 }; |
|
240 |
|
241 enum TDataState |
|
242 /** |
|
243 The TDataState enumeration defines the state of the message parser as |
|
244 regards to the current data packet. |
|
245 */ |
|
246 { |
|
247 /** The composer is waiting for more message info to be available to be |
|
248 able to continue composing. |
|
249 */ |
|
250 EWaitingForInfo = 0, |
|
251 |
|
252 /** The composer is creating the message from the available info. |
|
253 */ |
|
254 EGotInfo, |
|
255 |
|
256 /** The composer is waiting for the observer to release the current data |
|
257 buffer before continuing to compose the message. |
|
258 */ |
|
259 EWaitingForRelease, |
|
260 |
|
261 /** The composer has been reset. |
|
262 */ |
|
263 EReset |
|
264 }; |
|
265 |
|
266 enum TComposingStatus |
|
267 /** |
|
268 The TComposingStatus enumeration defines the status of composing for the |
|
269 current state of the composer. |
|
270 */ |
|
271 { |
|
272 /** The current state has been completed. |
|
273 */ |
|
274 ESectionDone = 0, |
|
275 |
|
276 /** The current state has not been completed. |
|
277 */ |
|
278 ESectionNotDone, |
|
279 |
|
280 /** The current data packet should be sent. |
|
281 */ |
|
282 ESendData, |
|
283 |
|
284 /** The composer should not continue. Either the message is complete or |
|
285 more message info is required to continue. |
|
286 */ |
|
287 EStop |
|
288 }; |
|
289 |
|
290 private: // methods from CActive |
|
291 |
|
292 virtual void RunL(); |
|
293 virtual void DoCancel(); |
|
294 virtual TInt RunError(TInt aError); |
|
295 |
|
296 private: // methods from MHttpBufferSupplier |
|
297 |
|
298 virtual void ReAllocBufferL(TInt aRequiredSize, TPtr8& aBuffer); |
|
299 virtual void DeleteBuffer(); |
|
300 |
|
301 private: // methods |
|
302 |
|
303 CHttpMessageComposer(MHttpMessageComposerObserver& aObserver); |
|
304 |
|
305 TComposingStatus ComposeStartLineL(); |
|
306 TComposingStatus ComposeHeadersL(); |
|
307 TComposingStatus ComposeSingleHeaderL(); |
|
308 TComposingStatus ComposeChunkSizeL(); |
|
309 TComposingStatus ComposeLastChunkL(); |
|
310 TComposingStatus ComposeTrailerL(); |
|
311 |
|
312 void CompleteSelf(); |
|
313 void DoReset(); |
|
314 |
|
315 private: // attributes |
|
316 |
|
317 MHttpMessageComposerObserver& iObserver; |
|
318 THttpDataComposer iDataComposer; |
|
319 TComposerState iState; |
|
320 TDataState iDataState; |
|
321 HBufC8* iDataBuffer; |
|
322 TPtrC8 iSendBuffer; |
|
323 MHTTPDataSupplier* iBodyData; |
|
324 TInt iDataSizeLeft; |
|
325 TBool iLastChunk; |
|
326 __DECLARE_PERFORMANCE_LOG |
|
327 }; |
|
328 |
|
329 #endif // __CHTTPMESSAGECOMPOSER_H__ |