@@ -218,13 +218,168 @@ void http_msg_base::_complete(utility::size64_t body_size, const std::exception_
218
218
}
219
219
}
220
220
221
+ static bool is_content_type_one_of (const utility::string_t *first, const utility::string_t *last, const utility::string_t &value)
222
+ {
223
+ while (first != last)
224
+ {
225
+ if (utility::details::str_icmp (*first, value))
226
+ {
227
+ return true ;
228
+ }
229
+ ++first;
230
+ }
231
+ return false ;
232
+ }
233
+
234
+ // Remove once VS 2013 is no longer supported.
235
+ #if defined(_WIN32) && _MSC_VER < 1900
236
+ // Not referring to mime_types to avoid static initialization order fiasco.
237
+ static const utility::string_t textual_types [] = {
238
+ U (" message/http" ),
239
+ U (" application/json" ),
240
+ U (" application/xml" ),
241
+ U (" application/atom+xml" ),
242
+ U (" application/http" ),
243
+ U (" application/x-www-form-urlencoded" )
244
+ };
245
+ #endif
246
+
247
+ // / <summary>
248
+ // / Determines whether or not the given content type is 'textual' according the feature specifications.
249
+ // / </summary>
250
+ static bool is_content_type_textual (const utility::string_t &content_type)
251
+ {
252
+ #if !defined(_WIN32) || _MSC_VER >= 1900
253
+ static const utility::string_t textual_types [] = {
254
+ mime_types::message_http,
255
+ mime_types::application_json,
256
+ mime_types::application_xml,
257
+ mime_types::application_atom_xml,
258
+ mime_types::application_http,
259
+ mime_types::application_x_www_form_urlencoded
260
+ };
261
+ #endif
262
+
263
+ if (content_type.size () >= 4 && utility::details::str_icmp (content_type.substr (0 , 4 ), _XPLATSTR (" text" )))
264
+ {
265
+ return true ;
266
+ }
267
+ return (is_content_type_one_of (std::begin (textual_types), std::end (textual_types), content_type));
268
+ }
269
+
270
+ // Remove once VS 2013 is no longer supported.
271
+ #if defined(_WIN32) && _MSC_VER < 1900
272
+ // Not referring to mime_types to avoid static initialization order fiasco.
273
+ static const utility::string_t json_types [] = {
274
+ U (" application/json" ),
275
+ U (" application/x-json" ),
276
+ U (" text/json" ),
277
+ U (" text/x-json" ),
278
+ U (" text/javascript" ),
279
+ U (" text/x-javascript" ),
280
+ U (" application/javascript" ),
281
+ U (" application/x-javascript" )
282
+ };
283
+ #endif
284
+
285
+ // / <summary>
286
+ // / Determines whether or not the given content type is JSON according the feature specifications.
287
+ // / </summary>
288
+ static bool is_content_type_json (const utility::string_t &content_type)
289
+ {
290
+ #if !defined(_WIN32) || _MSC_VER >= 1900
291
+ static const utility::string_t json_types [] = {
292
+ mime_types::application_json,
293
+ mime_types::application_xjson,
294
+ mime_types::text_json,
295
+ mime_types::text_xjson,
296
+ mime_types::text_javascript,
297
+ mime_types::text_xjavascript,
298
+ mime_types::application_javascript,
299
+ mime_types::application_xjavascript
300
+ };
301
+ #endif
302
+
303
+ return (is_content_type_one_of (std::begin (json_types), std::end (json_types), content_type));
304
+ }
305
+
306
+ // / <summary>
307
+ // / Gets the default charset for given content type. If the MIME type is not textual or recognized Latin1 will be returned.
308
+ // / </summary>
309
+ static utility::string_t get_default_charset (const utility::string_t &content_type)
310
+ {
311
+ // We are defaulting everything to Latin1 except JSON which is utf-8.
312
+ if (is_content_type_json (content_type))
313
+ {
314
+ return charset_types::utf8;
315
+ }
316
+ else
317
+ {
318
+ return charset_types::latin1;
319
+ }
320
+ }
321
+
322
+
323
+ // / <summary>
324
+ // / Parses the given Content-Type header value to get out actual content type and charset.
325
+ // / If the charset isn't specified the default charset for the content type will be set.
326
+ // / </summary>
327
+ static void parse_content_type_and_charset (const utility::string_t &content_type, utility::string_t &content, utility::string_t &charset)
328
+ {
329
+ const size_t semi_colon_index = content_type.find_first_of (_XPLATSTR (" ;" ));
330
+
331
+ // No charset specified.
332
+ if (semi_colon_index == utility::string_t ::npos)
333
+ {
334
+ content = content_type;
335
+ trim_whitespace (content);
336
+ charset = get_default_charset (content);
337
+ return ;
338
+ }
339
+
340
+ // Split into content type and second part which could be charset.
341
+ content = content_type.substr (0 , semi_colon_index);
342
+ trim_whitespace (content);
343
+ utility::string_t possible_charset = content_type.substr (semi_colon_index + 1 );
344
+ trim_whitespace (possible_charset);
345
+ const size_t equals_index = possible_charset.find_first_of (_XPLATSTR (" =" ));
346
+
347
+ // No charset specified.
348
+ if (equals_index == utility::string_t ::npos)
349
+ {
350
+ charset = get_default_charset (content);
351
+ return ;
352
+ }
353
+
354
+ // Split and make sure 'charset'
355
+ utility::string_t charset_key = possible_charset.substr (0 , equals_index);
356
+ trim_whitespace (charset_key);
357
+ if (!utility::details::str_icmp (charset_key, _XPLATSTR (" charset" )))
358
+ {
359
+ charset = get_default_charset (content);
360
+ return ;
361
+ }
362
+ charset = possible_charset.substr (equals_index + 1 );
363
+ // Remove the redundant ';' at the end of charset.
364
+ while (charset.back () == ' ;' )
365
+ {
366
+ charset.pop_back ();
367
+ }
368
+ trim_whitespace (charset);
369
+ if (charset.front () == _XPLATSTR (' "' ) && charset.back () == _XPLATSTR (' "' ))
370
+ {
371
+ charset = charset.substr (1 , charset.size () - 2 );
372
+ trim_whitespace (charset);
373
+ }
374
+ }
375
+
221
376
utility::string_t details::http_msg_base::parse_and_check_content_type (bool ignore_content_type, const std::function<bool (const utility::string_t &)> &check_content_type)
222
377
{
223
378
if (!instream ())
224
379
{
225
380
throw http_exception (stream_was_set_explicitly);
226
381
}
227
-
382
+
228
383
utility::string_t content, charset = charset_types::utf8;
229
384
if (!ignore_content_type)
230
385
{
0 commit comments