View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.hc.client5.http.entity.mime;
29  
30  import java.io.IOException;
31  import java.io.OutputStream;
32  import java.nio.charset.Charset;
33  import java.nio.charset.StandardCharsets;
34  import java.util.List;
35  
36  import org.apache.hc.core5.http.NameValuePair;
37  import org.apache.hc.core5.net.PercentCodec;
38  
39  class HttpRFC7578Multipart extends AbstractMultipartFormat {
40  
41      private final List<MultipartPart> parts;
42  
43      /**
44       * Constructs a new instance of {@code HttpRFC7578Multipart} with the given charset, boundary, parts, preamble, and epilogue.
45       *
46       * @param charset  the charset to use.
47       * @param boundary the boundary string to use.
48       * @param parts    the list of parts to include in the multipart message.
49       * @param preamble the optional preamble string to include before the first part. May be {@code null}.
50       * @param epilogue the optional epilogue string to include after the last part. May be {@code null}.
51       */
52      public HttpRFC7578Multipart(
53          final Charset charset,
54          final String boundary,
55          final List<MultipartPart> parts,
56          final String preamble,
57          final String epilogue) {
58          super(charset, boundary, preamble, epilogue);
59          this.parts = parts;
60      }
61  
62      /**
63       * Constructs a new instance of {@code HttpRFC7578Multipart} with the given charset, boundary, and parts.
64       *
65       * @param charset  the charset to use.
66       * @param boundary the boundary string to use.
67       * @param parts    the list of parts to include in the multipart message.
68       */
69      public HttpRFC7578Multipart(
70              final Charset charset,
71              final String boundary,
72              final List<MultipartPart> parts) {
73          this(charset,boundary,parts,null, null);
74      }
75  
76      @Override
77      public List<MultipartPart> getParts() {
78          return parts;
79      }
80  
81      @Override
82      protected void formatMultipartHeader(final MultipartPart part, final OutputStream out) throws IOException {
83          for (final MimeField field: part.getHeader()) {
84              if (MimeConsts.CONTENT_DISPOSITION.equalsIgnoreCase(field.getName())) {
85                  writeBytes(field.getName(), charset, out);
86                  writeBytes(FIELD_SEP, out);
87                  writeBytes(field.getValue(), out);
88                  final List<NameValuePair> parameters = field.getParameters();
89                  for (int i = 0; i < parameters.size(); i++) {
90                      final NameValuePair parameter = parameters.get(i);
91                      final String name = parameter.getName();
92                      final String value = parameter.getValue();
93                      writeBytes("; ", out);
94                      writeBytes(name, out);
95                      writeBytes("=\"", out);
96                      if (value != null) {
97                          if (name.equalsIgnoreCase(MimeConsts.FIELD_PARAM_FILENAME) ||
98                                  name.equalsIgnoreCase(MimeConsts.FIELD_PARAM_FILENAME_START)) {
99                              final String encodedValue = name.equalsIgnoreCase(MimeConsts.FIELD_PARAM_FILENAME_START) ?
100                                     "UTF-8''" + PercentCodec.RFC5987.encode(value) : PercentCodec.RFC5987.encode(value);
101                             final byte[] encodedBytes = encodedValue.getBytes(StandardCharsets.US_ASCII);
102                             out.write(encodedBytes);
103                         } else {
104                             writeBytes(value, out);
105                         }
106                     }
107                     writeBytes("\"", out);
108                 }
109                 writeBytes(CR_LF, out);
110             } else {
111                 writeField(field, charset, out);
112             }
113         }
114     }
115 
116 }