summaryrefslogtreecommitdiffstats
path: root/net/http/http_content_disposition.cc
blob: 52d9f4fdf2435e80b4394910d19a8d1ad33c4839 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_content_disposition.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "net/base/net_util.h"
#include "net/http/http_util.h"

namespace net {

HttpContentDisposition::HttpContentDisposition(
    const std::string& header, const std::string& referrer_charset)
  : type_(INLINE) {
  Parse(header, referrer_charset);
}

HttpContentDisposition::~HttpContentDisposition() {
}

std::string::const_iterator HttpContentDisposition::ConsumeDispositionType(
    std::string::const_iterator begin, std::string::const_iterator end) {
  DCHECK(type_ == INLINE);
  std::string::const_iterator delimiter = std::find(begin, end, ';');

  std::string::const_iterator type_begin = begin;
  std::string::const_iterator type_end = delimiter;
  HttpUtil::TrimLWS(&type_begin, &type_end);

  // If the disposition-type isn't a valid token the then the
  // Content-Disposition header is malformed, and we treat the first bytes as
  // a parameter rather than a disposition-type.
  if (!HttpUtil::IsToken(type_begin, type_end))
    return begin;

  DCHECK(std::find(type_begin, type_end, '=') == type_end);

  if (!LowerCaseEqualsASCII(type_begin, type_end, "inline"))
    type_ = ATTACHMENT;
  return delimiter;
}

// http://tools.ietf.org/html/rfc6266
//
//  content-disposition = "Content-Disposition" ":"
//                         disposition-type *( ";" disposition-parm )
//
//  disposition-type    = "inline" | "attachment" | disp-ext-type
//                      ; case-insensitive
//  disp-ext-type       = token
//
//  disposition-parm    = filename-parm | disp-ext-parm
//
//  filename-parm       = "filename" "=" value
//                      | "filename*" "=" ext-value
//
//  disp-ext-parm       = token "=" value
//                      | ext-token "=" ext-value
//  ext-token           = <the characters in token, followed by "*">
//
void HttpContentDisposition::Parse(const std::string& header,
                                   const std::string& referrer_charset) {
  DCHECK(type_ == INLINE);
  DCHECK(filename_.empty());

  std::string::const_iterator pos = header.begin();
  std::string::const_iterator end = header.end();
  pos = ConsumeDispositionType(pos, end);

  std::string name;
  std::string filename;
  std::string ext_filename;

  HttpUtil::NameValuePairsIterator iter(pos, end, ';');
  while (iter.GetNext()) {
    if (filename.empty() && LowerCaseEqualsASCII(iter.name_begin(),
                                                 iter.name_end(),
                                                 "filename")) {
      DecodeFilenameValue(iter.value(), referrer_charset, &filename);
    } else if (name.empty() && LowerCaseEqualsASCII(iter.name_begin(),
                                                    iter.name_end(),
                                                    "name")) {
      DecodeFilenameValue(iter.value(), referrer_charset, &name);
    } else if (ext_filename.empty() && LowerCaseEqualsASCII(iter.name_begin(),
                                                            iter.name_end(),
                                                            "filename*")) {
      DecodeExtValue(iter.raw_value(), &ext_filename);
    }
  }

  if (!ext_filename.empty())
    filename_ = ext_filename;
  else if (!filename.empty())
    filename_ = filename;
  else
    filename_ = name;
}

}  // namespace net