|
1 // Copyright (c) 2002-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 #include "chttpgeneralheaderwriter.h" |
|
17 |
|
18 #include <http/rhttpsession.h> |
|
19 #include <httpstringconstants.h> |
|
20 #include <httperr.h> |
|
21 |
|
22 #include "CHeaderField.h" |
|
23 |
|
24 _LIT8(KSemiSpaceSep,"; "); |
|
25 |
|
26 CHttpGeneralHeaderWriter* CHttpGeneralHeaderWriter::NewL(RStringPool aStringPool) |
|
27 /** |
|
28 Factory constructor. |
|
29 @internalComponent |
|
30 @param aStringPool The current string pool. |
|
31 @return A pointer to a fully initialised object. |
|
32 @leave KErrNoMemory Not enough memory to create object. |
|
33 */ |
|
34 { |
|
35 return new(ELeave)CHttpGeneralHeaderWriter(aStringPool); |
|
36 } |
|
37 |
|
38 CHttpGeneralHeaderWriter::~CHttpGeneralHeaderWriter() |
|
39 /** |
|
40 Destructor |
|
41 @internalComponent |
|
42 */ |
|
43 { |
|
44 } |
|
45 |
|
46 CHttpGeneralHeaderWriter::CHttpGeneralHeaderWriter(RStringPool aStringPool) |
|
47 : CHttpHeaderWriter(aStringPool) |
|
48 /** |
|
49 Constructor |
|
50 @internalComponent |
|
51 @param aStringPool The current string pool. |
|
52 */ |
|
53 { |
|
54 } |
|
55 |
|
56 void CHttpGeneralHeaderWriter::EncodeCacheControlL(RHeaderField& aHeader) const |
|
57 /** |
|
58 Encodes a Cache-Control header. RFC 2616 section 14.9 - |
|
59 |
|
60 Cache-Control = "Cache-Control" ":" 1#cache-directive |
|
61 cache-directive = cache-request-directive |
|
62 | cache-response-directive |
|
63 cache-request-directive = "no-cache" |
|
64 | "no-store" |
|
65 | "max-age" "=" delta-seconds |
|
66 | "max-stale" [ "=" delta-seconds ] |
|
67 | "min-fresh" "=" delta-seconds |
|
68 | "no-transform" |
|
69 | "only-if-cached" |
|
70 | cache-extension |
|
71 |
|
72 cache-response-directive= "public" |
|
73 | "private" [ "=" <"> 1#field-name <"> ] |
|
74 | "no-cache" [ "=" <"> 1#field-name <"> ] |
|
75 | "no-store" |
|
76 | "no-transform" |
|
77 | "must-revalidate" |
|
78 | "proxy-revalidate" |
|
79 | "max-age" "=" delta-seconds |
|
80 | "s-maxage" "=" delta-seconds |
|
81 | cache-extension |
|
82 |
|
83 cache-extension = token [ "=" ( token | quoted-string ) ] |
|
84 |
|
85 The cache-control header value is a comma separated list of values with at |
|
86 least one value. |
|
87 @internalComponent |
|
88 @param aHeader The cache-control header field to encode. |
|
89 @leave CHttpWriter::DoTokenCsvListHeaderL |
|
90 @todo Is there any point in this? Why not call DoTokenCsvListHeaderL() |
|
91 directly |
|
92 */ |
|
93 { |
|
94 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeCacheControl); |
|
95 } |
|
96 |
|
97 void CHttpGeneralHeaderWriter::EncodeConnectionL(RHeaderField& aHeader) const |
|
98 /** |
|
99 Decodes the Connection header. RFC2616 section 14.10 - |
|
100 |
|
101 Connection = "Connection" ":" 1#(connection-token) |
|
102 connection-token = token |
|
103 The connection header value is a comma separated list of values with at least |
|
104 one value. |
|
105 @internalComponent |
|
106 @param aHeader The connection header field to encode. |
|
107 @leave CHttpWriter::DoTokenCsvListHeaderL |
|
108 @todo Is there any point in this? Why not call DoTokenCsvListHeaderL() |
|
109 directly |
|
110 */ |
|
111 { |
|
112 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeConnection); |
|
113 } |
|
114 |
|
115 void CHttpGeneralHeaderWriter::EncodeDateL(RHeaderField& aHeader) const |
|
116 /** |
|
117 Encodes the date header. RFC2616 section 14.18 - |
|
118 |
|
119 Date = "Date" ":" HTTP-Date |
|
120 |
|
121 The HTTP-Date format has a few formats. E.g. Date: Tue, 15 Nov 1994 08:12:31 GMT |
|
122 @internalComponent |
|
123 @param aHeader The date header field to encode. |
|
124 @leave CHttpWriter::EncodeGenericDateL |
|
125 @todo Is there any point in this? Why not call EncodeGenericDateL() |
|
126 directly |
|
127 */ |
|
128 { |
|
129 EncodeGenericDateL(aHeader, KErrHttpEncodeDate); |
|
130 } |
|
131 |
|
132 void CHttpGeneralHeaderWriter::EncodeTransferEncodingL(RHeaderField& aHeader) const |
|
133 /** |
|
134 Encodes the transfer-encoding header. RFC2616 section 14.41 - |
|
135 |
|
136 Transfer-Encoding = "Transfer-Encoding" ":" 1#transfer-coding |
|
137 transfer-coding = "chunked" | transfer-extension |
|
138 transfer-extension = token *( ";" parameter ) |
|
139 parameter = attribute "=" value |
|
140 attribute = token |
|
141 value = token | quoted-string |
|
142 |
|
143 The transfer-encoding header is a comma separated list of values with at |
|
144 least one value. |
|
145 @internalComponent |
|
146 @param aHeader The transfer-encoding header field to encode. |
|
147 @leave CHttpWriter::DoTokenCsvListHeaderL |
|
148 @todo Is there any point in this? Why not call DoTokenCsvListHeaderL() |
|
149 directly |
|
150 */ |
|
151 { |
|
152 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeTransferEncoding); |
|
153 } |
|
154 |
|
155 void CHttpGeneralHeaderWriter::EncodeContentTypeL(RHeaderField& aHeader) const |
|
156 /** |
|
157 Encodes the content-type header. RFC2616 section 14.17 |
|
158 |
|
159 Content-Type = "Content-Type" ":" media-type |
|
160 media-type = type "/" subtype *( ";" parameter ) |
|
161 type = token |
|
162 subtype = token |
|
163 parameter = attribute '=' value |
|
164 attribute = token |
|
165 value = token | quoted-string |
|
166 |
|
167 The content-type header has a single media-type value. The atttribute |
|
168 is normally the 'charset'. E.g. Content-Type: text/html; charset=ISO-8859-4 |
|
169 @internalComponent |
|
170 @param aHeader The content-type header field to encode. |
|
171 @leave RHeaderField::BeginRawDataL |
|
172 @leave RHeaderField::WriteRawDataL |
|
173 @leave CHttpWriter::WriteRawStrFPartL |
|
174 @leave KErrHttpEncodeContentType There are no value tokens, the |
|
175 parameter was empty or the parameter |
|
176 was not a string type value. |
|
177 */ |
|
178 { |
|
179 __START_PERFORMANCE_LOGGER(); |
|
180 // Check part 1 |
|
181 THeaderFieldPartIter iter = aHeader.PartsL(); |
|
182 iter.First(); |
|
183 if( iter.AtEnd() ) |
|
184 { |
|
185 // The header value is empty! |
|
186 User::Leave(KErrHttpEncodeContentType); |
|
187 } |
|
188 aHeader.BeginRawDataL(); |
|
189 const CHeaderFieldPart* part = WriteRawStrFPartL(aHeader, iter, KErrHttpEncodeContentType); |
|
190 |
|
191 // Check for parameters... |
|
192 THeaderFieldParamIter iter2 = part->Parameters(); |
|
193 iter2.First(); |
|
194 while( !iter2.AtEnd() ) |
|
195 { |
|
196 // Got a parameter - write a semicolon separator |
|
197 aHeader.WriteRawDataL(KSemiSpaceSep); |
|
198 const CHeaderFieldParam* param = iter2(); |
|
199 if( !param ) |
|
200 { |
|
201 // Empty parameter! |
|
202 User::Leave(KErrHttpEncodeContentType); |
|
203 } |
|
204 // Anticipate only string parameter values |
|
205 THTTPHdrVal paramVal = param->Value(); |
|
206 if( paramVal.Type() != THTTPHdrVal::KStrFVal ) |
|
207 { |
|
208 // Was not a string value... |
|
209 User::Leave(KErrHttpEncodeContentType); |
|
210 } |
|
211 RStringF paramName = iStringPool.StringF(param->Name()); |
|
212 aHeader.WriteRawDataL(paramName.DesC()); |
|
213 aHeader.WriteRawDataL('='); |
|
214 aHeader.WriteRawDataL(paramVal.StrF().DesC()); |
|
215 |
|
216 // Move onto the next parameter, writing a separator as necessary |
|
217 ++iter2; |
|
218 } |
|
219 // All done! |
|
220 aHeader.CommitRawData(); |
|
221 __END_PERFORMANCE_LOGGER(_L(",CHttpGeneralHeaderWriter::EncodeContentTypeL()")); |
|
222 } |
|
223 |
|
224 void CHttpGeneralHeaderWriter::EncodeContentLengthL(RHeaderField& aHeader) const |
|
225 /** |
|
226 Encodes the content-length header. RFC2616 section 14.13 - |
|
227 |
|
228 Content-Length = "Content-Length" ":" 1*DIGIT |
|
229 |
|
230 The content-length value is a number with at least one digit. |
|
231 @internalComponent |
|
232 @param aHeader The content-length header field to encode. |
|
233 @leave CHttpWriter::EncodeGenericNumberHeaderL |
|
234 @todo Is there any point in this? Why not call EncodeGenericNumberHeaderL() |
|
235 directly. |
|
236 */ |
|
237 { |
|
238 EncodeGenericNumberHeaderL(aHeader, KErrHttpEncodeContentLength); |
|
239 } |
|
240 |
|
241 /* |
|
242 * Methods from CHeaderWriter |
|
243 */ |
|
244 |
|
245 void CHttpGeneralHeaderWriter::EncodeHeaderL(RHeaderField& aHeader) |
|
246 /** |
|
247 Encodes the header field value. |
|
248 @internalComponent |
|
249 @param aHeader The header field to be encoded. |
|
250 @leave CHttpGeneralHeaderWriter::EncodeCacheControlL |
|
251 @leave CHttpGeneralHeaderWriter::EncodeConnectionL |
|
252 @leave CHttpGeneralHeaderWriter::EncodeDateL |
|
253 @leave CHttpGeneralHeaderWriter::EncodeTransferEncodingL |
|
254 @leave CHttpGeneralHeaderWriter::EncodeContentLengthL |
|
255 @leave CHttpWriter::DoTokenCsvListHeaderL |
|
256 @leave KErrNotSupported The writer was asked to encode a header that |
|
257 is does not support. |
|
258 */ |
|
259 { |
|
260 RStringF fieldStr = iStringPool.StringF(aHeader.Name()); |
|
261 switch( fieldStr.Index(iStringTable) ) |
|
262 { |
|
263 case HTTP::ECacheControl: |
|
264 { |
|
265 EncodeCacheControlL(aHeader); |
|
266 } break; |
|
267 case HTTP::EConnection: |
|
268 { |
|
269 EncodeConnectionL(aHeader); |
|
270 } break; |
|
271 case HTTP::EDate: |
|
272 { |
|
273 EncodeDateL(aHeader); |
|
274 } break; |
|
275 case HTTP::EPragma: |
|
276 { |
|
277 // RFC2616 section 14.32 - |
|
278 // |
|
279 // Pragma = "Pragma" ":" 1#pragma-directive |
|
280 // pragma-directive = "no-cache" | extension-pragma |
|
281 // extension-pragma = token [ "=" ( token ! quoted-string ) ] |
|
282 // |
|
283 // The pragma header value is a comma separated list of values with at |
|
284 // least one value. |
|
285 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodePragma); |
|
286 } break; |
|
287 case HTTP::ETransferEncoding: |
|
288 { |
|
289 EncodeTransferEncodingL(aHeader); |
|
290 } break; |
|
291 case HTTP::EContentEncoding: |
|
292 { |
|
293 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentEncoding); |
|
294 } break; |
|
295 case HTTP::EContentLanguage: |
|
296 { |
|
297 // RFC2616 section 14.12 - |
|
298 // |
|
299 // Content-Language = "Content-Language" ":" 1#language-tag |
|
300 // |
|
301 // The content-language header value is a comma separated list of values |
|
302 // with at least one value. |
|
303 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentLanguage); |
|
304 } break; |
|
305 case HTTP::EUpgrade: |
|
306 { |
|
307 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeUpgrade); |
|
308 } break; |
|
309 case HTTP::EContentLength: |
|
310 { |
|
311 EncodeContentLengthL(aHeader); |
|
312 } break; |
|
313 case HTTP::EContentLocation: |
|
314 { |
|
315 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentLocation); |
|
316 } break; |
|
317 case HTTP::EContentMD5: |
|
318 { |
|
319 DoTokenCsvListHeaderL(aHeader, KErrHttpEncodeContentMD5); |
|
320 } break; |
|
321 case HTTP::EContentType: |
|
322 { |
|
323 EncodeContentTypeL(aHeader); |
|
324 } break; |
|
325 case HTTP::EExpires: |
|
326 case HTTP::ELastModified: |
|
327 { |
|
328 EncodeDateL(aHeader); |
|
329 }break; |
|
330 default: |
|
331 User::Leave(KErrNotSupported); |
|
332 break; |
|
333 } |
|
334 } |