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 package org.apache.hc.client5.http.entity.mime;
29
30 import java.io.ByteArrayOutputStream;
31 import java.io.IOException;
32 import java.io.OutputStream;
33 import java.nio.ByteBuffer;
34 import java.nio.CharBuffer;
35 import java.nio.charset.Charset;
36 import java.nio.charset.StandardCharsets;
37 import java.util.List;
38
39 import org.apache.hc.core5.util.Args;
40 import org.apache.hc.core5.util.ByteArrayBuffer;
41
42
43
44
45
46
47 abstract class AbstractMultipartFormat {
48
49 static ByteArrayBuffer encode(
50 final Charset charset, final String string) {
51 final ByteBuffer encoded = charset.encode(CharBuffer.wrap(string));
52 final ByteArrayBuffer bab = new ByteArrayBuffer(encoded.remaining());
53 bab.append(encoded.array(), encoded.arrayOffset() + encoded.position(), encoded.remaining());
54 return bab;
55 }
56
57 static void writeBytes(
58 final ByteArrayBuffer b, final OutputStream out) throws IOException {
59 out.write(b.array(), 0, b.length());
60 }
61
62 static void writeBytes(
63 final String s, final Charset charset, final OutputStream out) throws IOException {
64 final ByteArrayBuffer b = encode(charset, s);
65 writeBytes(b, out);
66 }
67
68 static void writeBytes(
69 final String s, final OutputStream out) throws IOException {
70 final ByteArrayBuffer b = encode(StandardCharsets.ISO_8859_1, s);
71 writeBytes(b, out);
72 }
73
74 static void writeField(
75 final MimeField field, final OutputStream out) throws IOException {
76 writeBytes(field.getName(), out);
77 writeBytes(FIELD_SEP, out);
78 writeBytes(field.getBody(), out);
79 writeBytes(CR_LF, out);
80 }
81
82 static void writeField(
83 final MimeField field, final Charset charset, final OutputStream out) throws IOException {
84 writeBytes(field.getName(), charset, out);
85 writeBytes(FIELD_SEP, out);
86 writeBytes(field.getBody(), charset, out);
87 writeBytes(CR_LF, out);
88 }
89
90 static final ByteArrayBuffer FIELD_SEP = encode(StandardCharsets.ISO_8859_1, ": ");
91 static final ByteArrayBuffer CR_LF = encode(StandardCharsets.ISO_8859_1, "\r\n");
92 static final ByteArrayBuffer TWO_HYPHENS = encode(StandardCharsets.ISO_8859_1, "--");
93
94 final Charset charset;
95 final String boundary;
96
97
98
99
100
101
102
103
104 public AbstractMultipartFormat(final Charset charset, final String boundary) {
105 super();
106 Args.notNull(boundary, "Multipart boundary");
107 this.charset = charset != null ? charset : StandardCharsets.ISO_8859_1;
108 this.boundary = boundary;
109 }
110
111 public AbstractMultipartFormat(final String boundary) {
112 this(null, boundary);
113 }
114
115 public abstract List<MultipartPart> getParts();
116
117 void doWriteTo(
118 final OutputStream out,
119 final boolean writeContent) throws IOException {
120
121 final ByteArrayBuffer boundaryEncoded = encode(this.charset, this.boundary);
122 for (final MultipartPart part: getParts()) {
123 writeBytes(TWO_HYPHENS, out);
124 writeBytes(boundaryEncoded, out);
125 writeBytes(CR_LF, out);
126
127 formatMultipartHeader(part, out);
128
129 writeBytes(CR_LF, out);
130
131 if (writeContent) {
132 part.getBody().writeTo(out);
133 }
134 writeBytes(CR_LF, out);
135 }
136 writeBytes(TWO_HYPHENS, out);
137 writeBytes(boundaryEncoded, out);
138 writeBytes(TWO_HYPHENS, out);
139 writeBytes(CR_LF, out);
140 }
141
142
143
144
145 protected abstract void formatMultipartHeader(
146 final MultipartPart part,
147 final OutputStream out) throws IOException;
148
149
150
151
152
153
154 public void writeTo(final OutputStream out) throws IOException {
155 doWriteTo(out, true);
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172 public long getTotalLength() {
173 long contentLen = 0;
174 for (final MultipartPart part: getParts()) {
175 final ContentBody body = part.getBody();
176 final long len = body.getContentLength();
177 if (len >= 0) {
178 contentLen += len;
179 } else {
180 return -1;
181 }
182 }
183 final ByteArrayOutputStream out = new ByteArrayOutputStream();
184 try {
185 doWriteTo(out, false);
186 final byte[] extra = out.toByteArray();
187 return contentLen + extra.length;
188 } catch (final IOException ex) {
189
190 return -1;
191 }
192 }
193
194 }