1 /*
2 * Copyright (c) 2002-2026 Gargoyle Software Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.htmlunit.http;
16
17 import java.util.Collections;
18 import java.util.LinkedHashMap;
19 import java.util.Locale;
20 import java.util.Map;
21
22 /**
23 * The result of parsing a {@code Content-Disposition} header (RFC 6266, RFC 2183).
24 * <p>
25 * Parameter names are case-insensitive (stored lower case); if a parameter is
26 * defined more than once, the first one wins. The values are not sanitized.
27 * </p>
28 *
29 * @see ContentDispositionParser
30 *
31 * @author Ronald Brill
32 */
33 public final class ContentDisposition {
34
35 private final String type_;
36 private final Map<String, String> parameters_;
37 private final Map<String, String> extendedParameters_;
38
39 ContentDisposition(final String type, final Map<String, String> parameters,
40 final Map<String, String> extendedParameters) {
41 type_ = type;
42 parameters_ = Collections.unmodifiableMap(new LinkedHashMap<>(parameters));
43 extendedParameters_ = Collections.unmodifiableMap(new LinkedHashMap<>(extendedParameters));
44 }
45
46 /**
47 * Returns the disposition type.
48 *
49 * @return the disposition type in lower case (e.g. {@code attachment} or {@code inline});
50 * an empty string if the header has none
51 */
52 public String getType() {
53 return type_;
54 }
55
56 /**
57 * Checks the disposition type.
58 *
59 * @return {@code true} if the type is {@code attachment}
60 */
61 public boolean isAttachment() {
62 return "attachment".equals(type_);
63 }
64
65 /**
66 * Checks the disposition type.
67 *
68 * @return {@code true} if the type is {@code inline}
69 */
70 public boolean isInline() {
71 return "inline".equals(type_);
72 }
73
74 /**
75 * Returns the value of a plain parameter.
76 *
77 * @param name the name of the parameter (case-insensitive), without a trailing {@code *}
78 * @return the value of the plain parameter (quotes and escapes resolved) or {@code null};
79 * an empty string for a parameter without a value or with an empty value
80 */
81 public String getParameter(final String name) {
82 return parameters_.get(name.toLowerCase(Locale.ROOT));
83 }
84
85 /**
86 * Returns the decoded value of an extended parameter (RFC 8187).
87 *
88 * @param name the name of the parameter (case-insensitive), without the trailing {@code *}
89 * @return the decoded value of the extended parameter ({@code name*}, RFC 8187) or {@code null}
90 * if there is no such parameter or the value can not be decoded
91 */
92 public String getExtendedParameter(final String name) {
93 return extendedParameters_.get(name.toLowerCase(Locale.ROOT));
94 }
95
96 /**
97 * Returns all plain parameters.
98 *
99 * @return the plain parameters (lower case names, in header order); not modifiable
100 */
101 public Map<String, String> getParameters() {
102 return parameters_;
103 }
104
105 /**
106 * Returns the file name suggested by the server.
107 *
108 * @return the file name; the extended parameter {@code filename*} wins over {@code filename};
109 * {@code null} if there is none. The name is returned as sent by the server, so it is not
110 * safe to use it as file name without checking.
111 */
112 public String getFilename() {
113 final String extended = getExtendedParameter("filename");
114 return extended != null ? extended : getParameter("filename");
115 }
116 }