19
19
import java .io .ByteArrayOutputStream ;
20
20
import java .nio .charset .Charset ;
21
21
import java .nio .charset .StandardCharsets ;
22
+ import java .time .ZonedDateTime ;
23
+ import java .time .format .DateTimeParseException ;
22
24
23
25
import org .springframework .lang .Nullable ;
24
26
import org .springframework .util .Assert ;
25
27
import org .springframework .util .ObjectUtils ;
26
28
import org .springframework .util .StringUtils ;
27
29
28
30
import static java .nio .charset .StandardCharsets .*;
31
+ import static java .time .format .DateTimeFormatter .*;
29
32
30
33
/**
31
34
* Represent the Content-Disposition type and parameters as defined in RFC 2183.
@@ -47,18 +50,26 @@ public class ContentDisposition {
47
50
48
51
private final Long size ;
49
52
53
+ private final ZonedDateTime creationDate ;
54
+
55
+ private final ZonedDateTime modificationDate ;
56
+
57
+ private final ZonedDateTime readDate ;
58
+
50
59
51
60
/**
52
61
* Private constructor. See static factory methods in this class.
53
62
*/
54
- private ContentDisposition (@ Nullable String type , @ Nullable String name , @ Nullable String filename ,
55
- @ Nullable Charset charset , @ Nullable Long size ) {
56
-
63
+ private ContentDisposition (@ Nullable String type , @ Nullable String name , @ Nullable String filename , @ Nullable Charset charset , @ Nullable Long size ,
64
+ @ Nullable ZonedDateTime creationDate , @ Nullable ZonedDateTime modificationDate , @ Nullable ZonedDateTime readDate ) {
57
65
this .type = type ;
58
66
this .name = name ;
59
67
this .filename = filename ;
60
68
this .charset = charset ;
61
69
this .size = size ;
70
+ this .creationDate = creationDate ;
71
+ this .modificationDate = modificationDate ;
72
+ this .readDate = readDate ;
62
73
}
63
74
64
75
@@ -104,6 +115,30 @@ public Long getSize() {
104
115
return this .size ;
105
116
}
106
117
118
+ /**
119
+ * Return the value of the {@literal creation-date} parameter, or {@code null} if not defined.
120
+ */
121
+ @ Nullable
122
+ public ZonedDateTime getCreationDate () {
123
+ return this .creationDate ;
124
+ }
125
+
126
+ /**
127
+ * Return the value of the {@literal modification-date} parameter, or {@code null} if not defined.
128
+ */
129
+ @ Nullable
130
+ public ZonedDateTime getModificationDate () {
131
+ return this .modificationDate ;
132
+ }
133
+
134
+ /**
135
+ * Return the value of the {@literal read-date} parameter, or {@code null} if not defined.
136
+ */
137
+ @ Nullable
138
+ public ZonedDateTime getReadDate () {
139
+ return this .readDate ;
140
+ }
141
+
107
142
108
143
/**
109
144
* Return a builder for a {@code ContentDisposition}.
@@ -119,11 +154,12 @@ public static Builder builder(String type) {
119
154
* Return an empty content disposition.
120
155
*/
121
156
public static ContentDisposition empty () {
122
- return new ContentDisposition ("" , null , null , null , null );
157
+ return new ContentDisposition ("" , null , null , null , null , null , null , null );
123
158
}
124
159
125
160
/**
126
161
* Parse a {@literal Content-Disposition} header value as defined in RFC 2183.
162
+ *
127
163
* @param contentDisposition the {@literal Content-Disposition} header value
128
164
* @return the parsed content disposition
129
165
* @see #toString()
@@ -136,6 +172,9 @@ public static ContentDisposition parse(String contentDisposition) {
136
172
String filename = null ;
137
173
Charset charset = null ;
138
174
Long size = null ;
175
+ ZonedDateTime creationDate = null ;
176
+ ZonedDateTime modificationDate = null ;
177
+ ZonedDateTime readDate = null ;
139
178
for (int i = 1 ; i < parts .length ; i ++) {
140
179
String part = parts [i ];
141
180
int eqIndex = part .indexOf ('=' );
@@ -159,12 +198,36 @@ else if (attribute.equals("filename") && (filename == null)) {
159
198
else if (attribute .equals ("size" ) ) {
160
199
size = Long .parseLong (value );
161
200
}
201
+ else if (attribute .equals ("creation-date" )) {
202
+ try {
203
+ creationDate = ZonedDateTime .parse (value , RFC_1123_DATE_TIME );
204
+ }
205
+ catch (DateTimeParseException ex ) {
206
+ // ignore
207
+ }
208
+ }
209
+ else if (attribute .equals ("modification-date" )) {
210
+ try {
211
+ modificationDate = ZonedDateTime .parse (value , RFC_1123_DATE_TIME );
212
+ }
213
+ catch (DateTimeParseException ex ) {
214
+ // ignore
215
+ }
216
+ }
217
+ else if (attribute .equals ("read-date" )) {
218
+ try {
219
+ readDate = ZonedDateTime .parse (value , RFC_1123_DATE_TIME );
220
+ }
221
+ catch (DateTimeParseException ex ) {
222
+ // ignore
223
+ }
224
+ }
162
225
}
163
226
else {
164
227
throw new IllegalArgumentException ("Invalid content disposition format" );
165
228
}
166
229
}
167
- return new ContentDisposition (type , name , filename , charset , size );
230
+ return new ContentDisposition (type , name , filename , charset , size , creationDate , modificationDate , readDate );
168
231
}
169
232
170
233
/**
@@ -225,7 +288,10 @@ public boolean equals(Object other) {
225
288
ObjectUtils .nullSafeEquals (this .name , otherCd .name ) &&
226
289
ObjectUtils .nullSafeEquals (this .filename , otherCd .filename ) &&
227
290
ObjectUtils .nullSafeEquals (this .charset , otherCd .charset ) &&
228
- ObjectUtils .nullSafeEquals (this .size , otherCd .size ));
291
+ ObjectUtils .nullSafeEquals (this .size , otherCd .size ) &&
292
+ ObjectUtils .nullSafeEquals (this .creationDate , otherCd .creationDate )&&
293
+ ObjectUtils .nullSafeEquals (this .modificationDate , otherCd .modificationDate )&&
294
+ ObjectUtils .nullSafeEquals (this .readDate , otherCd .readDate ));
229
295
}
230
296
231
297
@ Override
@@ -235,6 +301,9 @@ public int hashCode() {
235
301
result = 31 * result + ObjectUtils .nullSafeHashCode (this .filename );
236
302
result = 31 * result + ObjectUtils .nullSafeHashCode (this .charset );
237
303
result = 31 * result + ObjectUtils .nullSafeHashCode (this .size );
304
+ result = 31 * result + (creationDate != null ? creationDate .hashCode () : 0 );
305
+ result = 31 * result + (modificationDate != null ? modificationDate .hashCode () : 0 );
306
+ result = 31 * result + (readDate != null ? readDate .hashCode () : 0 );
238
307
return result ;
239
308
}
240
309
@@ -266,6 +335,21 @@ public String toString() {
266
335
sb .append ("; size=" );
267
336
sb .append (this .size );
268
337
}
338
+ if (this .creationDate != null ) {
339
+ sb .append ("; creation-date=\" " );
340
+ sb .append (RFC_1123_DATE_TIME .format (this .creationDate ));
341
+ sb .append ('\"' );
342
+ }
343
+ if (this .modificationDate != null ) {
344
+ sb .append ("; modification-date=\" " );
345
+ sb .append (RFC_1123_DATE_TIME .format (this .modificationDate ));
346
+ sb .append ('\"' );
347
+ }
348
+ if (this .readDate != null ) {
349
+ sb .append ("; read-date=\" " );
350
+ sb .append (RFC_1123_DATE_TIME .format (this .readDate ));
351
+ sb .append ('\"' );
352
+ }
269
353
return sb .toString ();
270
354
}
271
355
@@ -332,6 +416,21 @@ public interface Builder {
332
416
*/
333
417
Builder size (Long size );
334
418
419
+ /**
420
+ * Set the value of the {@literal creation-date} parameter.
421
+ */
422
+ Builder creationDate (ZonedDateTime creationDate );
423
+
424
+ /**
425
+ * Set the value of the {@literal modification-date} parameter.
426
+ */
427
+ Builder modificationDate (ZonedDateTime modificationDate );
428
+
429
+ /**
430
+ * Set the value of the {@literal read-date} parameter.
431
+ */
432
+ Builder readDate (ZonedDateTime readDate );
433
+
335
434
/**
336
435
* Build the content disposition
337
436
*/
@@ -351,6 +450,13 @@ private static class BuilderImpl implements Builder {
351
450
352
451
private Long size ;
353
452
453
+ private ZonedDateTime creationDate ;
454
+
455
+ private ZonedDateTime modificationDate ;
456
+
457
+ private ZonedDateTime readDate ;
458
+
459
+
354
460
public BuilderImpl (String type ) {
355
461
Assert .hasText (type , "'type' must not be not empty" );
356
462
this .type = type ;
@@ -381,9 +487,28 @@ public Builder size(Long size) {
381
487
return this ;
382
488
}
383
489
490
+ @ Override
491
+ public Builder creationDate (ZonedDateTime creationDate ) {
492
+ this .creationDate = creationDate ;
493
+ return this ;
494
+ }
495
+
496
+ @ Override
497
+ public Builder modificationDate (ZonedDateTime modificationDate ) {
498
+ this .modificationDate = modificationDate ;
499
+ return this ;
500
+ }
501
+
502
+ @ Override
503
+ public Builder readDate (ZonedDateTime readDate ) {
504
+ this .readDate = readDate ;
505
+ return this ;
506
+ }
507
+
384
508
@ Override
385
509
public ContentDisposition build () {
386
- return new ContentDisposition (this .type , this .name , this .filename , this .charset , this .size );
510
+ return new ContentDisposition (this .type , this .name , this .filename , this .charset ,
511
+ this .size , this .creationDate , this .modificationDate , this .readDate );
387
512
}
388
513
}
389
514
0 commit comments