Skip to content

Commit 89f9f7b

Browse files
committed
Replace jakarta.activation with an internal MIME-type parser
1 parent 170b047 commit 89f9f7b

5 files changed

Lines changed: 216 additions & 31 deletions

File tree

client/src/main/java/org/asynchttpclient/request/body/multipart/FileLikePart.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
*/
1616
package org.asynchttpclient.request.body.multipart;
1717

18-
import jakarta.activation.MimetypesFileTypeMap;
19-
20-
import java.io.IOException;
21-
import java.io.InputStream;
2218
import java.nio.charset.Charset;
2319

2420
import static org.asynchttpclient.util.MiscUtils.withDefault;
@@ -28,16 +24,6 @@
2824
*/
2925
public abstract class FileLikePart extends PartBase {
3026

31-
private static final MimetypesFileTypeMap MIME_TYPES_FILE_TYPE_MAP;
32-
33-
static {
34-
try (InputStream is = FileLikePart.class.getResourceAsStream("ahc-mime.types")) {
35-
MIME_TYPES_FILE_TYPE_MAP = new MimetypesFileTypeMap(is);
36-
} catch (IOException e) {
37-
throw new ExceptionInInitializerError(e);
38-
}
39-
}
40-
4127
/**
4228
* Default content encoding of file attachments.
4329
*/
@@ -63,7 +49,7 @@ protected FileLikePart(String name, String contentType, Charset charset, String
6349
}
6450

6551
private static String computeContentType(String contentType, String fileName) {
66-
return contentType != null ? contentType : MIME_TYPES_FILE_TYPE_MAP.getContentType(withDefault(fileName, ""));
52+
return contentType != null ? contentType : MimeTypes.getContentType(withDefault(fileName, ""));
6753
}
6854

6955
public String getFileName() {
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright (c) 2026 AsyncHttpClient Project. All rights reserved.
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+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.asynchttpclient.request.body.multipart;
17+
18+
import java.io.BufferedReader;
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.io.InputStreamReader;
22+
import java.nio.charset.StandardCharsets;
23+
import java.util.Collections;
24+
import java.util.HashMap;
25+
import java.util.Locale;
26+
import java.util.Map;
27+
28+
/**
29+
* Maps file extensions to content types using the bundled {@code ahc-mime.types} resource.
30+
*
31+
* <p>This is a self-contained replacement for {@code jakarta.activation.MimetypesFileTypeMap}, which was
32+
* previously used solely to resolve the content type of {@link FileLikePart}s. The lookup mirrors the
33+
* {@code MimetypesFileTypeMap} contract: the extension is the substring after the last {@code '.'}, and an
34+
* unknown or missing extension resolves to {@value #DEFAULT_CONTENT_TYPE}. Unlike the original, the lookup is
35+
* case-insensitive and relies exclusively on the bundled resource, so detection is deterministic across
36+
* machines and classpaths.
37+
*/
38+
final class MimeTypes {
39+
40+
static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
41+
42+
/**
43+
* Lower-cased file extension to content type. Built once at class load from {@code ahc-mime.types}.
44+
*/
45+
private static final Map<String, String> EXTENSION_TO_CONTENT_TYPE;
46+
47+
static {
48+
Map<String, String> map = new HashMap<>();
49+
// The MimetypesFileTypeMap format: '#' comments, blank lines, and whitespace-delimited
50+
// "type ext1 ext2 ..." entries. A later mapping for the same extension wins, matching the
51+
// original Hashtable-based implementation.
52+
try (InputStream is = MimeTypes.class.getResourceAsStream("ahc-mime.types");
53+
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.ISO_8859_1))) {
54+
String line;
55+
while ((line = reader.readLine()) != null) {
56+
line = line.trim();
57+
if (line.isEmpty() || line.charAt(0) == '#') {
58+
continue;
59+
}
60+
String[] tokens = line.split("\\s+");
61+
for (int i = 1; i < tokens.length; i++) {
62+
map.put(tokens[i].toLowerCase(Locale.ROOT), tokens[0]);
63+
}
64+
}
65+
} catch (IOException e) {
66+
throw new ExceptionInInitializerError(e);
67+
}
68+
EXTENSION_TO_CONTENT_TYPE = Collections.unmodifiableMap(map);
69+
}
70+
71+
private MimeTypes() {
72+
// Prevent outside initialization
73+
}
74+
75+
/**
76+
* Resolves the content type for the given file name based on its extension.
77+
*
78+
* @param fileName the file name (may include a path; only the part after the last {@code '.'} is used)
79+
* @return the mapped content type, or {@value #DEFAULT_CONTENT_TYPE} if the extension is absent or unknown
80+
*/
81+
static String getContentType(String fileName) {
82+
int dot = fileName.lastIndexOf('.');
83+
if (dot < 0) {
84+
return DEFAULT_CONTENT_TYPE;
85+
}
86+
String extension = fileName.substring(dot + 1);
87+
if (extension.isEmpty()) {
88+
return DEFAULT_CONTENT_TYPE;
89+
}
90+
return EXTENSION_TO_CONTENT_TYPE.getOrDefault(extension.toLowerCase(Locale.ROOT), DEFAULT_CONTENT_TYPE);
91+
}
92+
}

client/src/main/resources/org/asynchttpclient/request/body/multipart/ahc-mime.types

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file maps Internet media types to unique file extension(s).
22
# Although created for httpd, this file is used by many software systems
3-
# and has been placed in the public domain for unlimited redisribution.
3+
# and has been placed in the public domain for unlimited redistribution.
44
#
55
# The table below contains both registered and (common) unregistered types.
66
# A type that has no unique extension can be ignored -- they are listed
@@ -94,6 +94,7 @@ application/ecmascript ecma
9494
# application/edi-consent
9595
# application/edi-x12
9696
# application/edifact
97+
# application/efi
9798
# application/emergencycalldata.comment+xml
9899
# application/emergencycalldata.deviceinfo+xml
99100
# application/emergencycalldata.providerinfo+xml
@@ -111,10 +112,9 @@ application/exi exi
111112
# application/fastsoap
112113
# application/fdt+xml
113114
# application/fits
114-
# application/font-sfnt
115115
application/font-tdpfr pfr
116-
application/font-woff woff
117116
# application/framework-attributes+xml
117+
# application/geo+json
118118
application/gml+xml gml
119119
application/gpx+xml gpx
120120
application/gxf gxf
@@ -142,7 +142,7 @@ application/ipfix ipfix
142142
application/java-archive jar
143143
application/java-serialized-object ser
144144
application/java-vm class
145-
application/javascript js
145+
# application/javascript
146146
# application/jose
147147
# application/jose+json
148148
# application/jrd+json
@@ -156,6 +156,7 @@ application/jsonml+json jsonml
156156
# application/kpml-request+xml
157157
# application/kpml-response+xml
158158
# application/ld+json
159+
# application/lgr+xml
159160
# application/link-format
160161
# application/load-control+xml
161162
application/lost+xml lostxml
@@ -358,13 +359,15 @@ application/vnd.3gpp.pic-bw-large plb
358359
application/vnd.3gpp.pic-bw-small psb
359360
application/vnd.3gpp.pic-bw-var pvb
360361
# application/vnd.3gpp.sms
362+
# application/vnd.3gpp.sms+xml
361363
# application/vnd.3gpp.srvcc-ext+xml
362364
# application/vnd.3gpp.srvcc-info+xml
363365
# application/vnd.3gpp.state-and-event-info+xml
364366
# application/vnd.3gpp.ussd+xml
365367
# application/vnd.3gpp2.bcmcsinfo+xml
366368
# application/vnd.3gpp2.sms
367369
application/vnd.3gpp2.tcap tcap
370+
# application/vnd.3lightssoftware.imagescal
368371
application/vnd.3m.post-it-notes pwn
369372
application/vnd.accpac.simply.aso aso
370373
application/vnd.accpac.simply.imp imp
@@ -383,6 +386,7 @@ application/vnd.ahead.space ahead
383386
application/vnd.airzip.filesecure.azf azf
384387
application/vnd.airzip.filesecure.azs azs
385388
application/vnd.amazon.ebook azw
389+
# application/vnd.amazon.mobi8-ebook
386390
application/vnd.americandynamics.acc acc
387391
application/vnd.amiga.ami ami
388392
# application/vnd.amundsen.maze+xml
@@ -419,6 +423,7 @@ application/vnd.businessobjects rep
419423
# application/vnd.cendio.thinlinc.clientconf
420424
# application/vnd.century-systems.tcp_stream
421425
application/vnd.chemdraw+xml cdxml
426+
# application/vnd.chess-pgn
422427
application/vnd.chipnuts.karaoke-mmd mmd
423428
application/vnd.cinderella cdy
424429
# application/vnd.cirpack.isdn-ext
@@ -432,9 +437,11 @@ application/vnd.cluetrust.cartomobile-config-pkg c11amz
432437
# application/vnd.collection+json
433438
# application/vnd.collection.doc+json
434439
# application/vnd.collection.next+json
440+
# application/vnd.comicbook+zip
435441
# application/vnd.commerce-battelle
436442
application/vnd.commonspace csp
437443
application/vnd.contact.cmsg cdbcmsg
444+
# application/vnd.coreos.ignition+json
438445
application/vnd.cosmocaller cmc
439446
application/vnd.crick.clicker clkx
440447
application/vnd.crick.clicker.keyboard clkk
@@ -578,6 +585,7 @@ application/vnd.genomatix.tuxedo txd
578585
# application/vnd.geo+json
579586
# application/vnd.geocube+xml
580587
application/vnd.geogebra.file ggb
588+
application/vnd.geogebra.slides ggs
581589
application/vnd.geogebra.tool ggt
582590
application/vnd.geometry-explorer gex gre
583591
application/vnd.geonext gxt
@@ -886,6 +894,8 @@ application/vnd.olpc-sugar xo
886894
application/vnd.oma.dd2+xml dd2
887895
# application/vnd.oma.drm.risd+xml
888896
# application/vnd.oma.group-usage-list+xml
897+
# application/vnd.oma.lwm2m+json
898+
# application/vnd.oma.lwm2m+tlv
889899
# application/vnd.oma.pal+xml
890900
# application/vnd.oma.poc.detailed-progress-report+xml
891901
# application/vnd.oma.poc.final-report+xml
@@ -899,6 +909,7 @@ application/vnd.oma.dd2+xml dd2
899909
# application/vnd.omads-file+xml
900910
# application/vnd.omads-folder+xml
901911
# application/vnd.omaloc-supl-init
912+
# application/vnd.onepager
902913
# application/vnd.openblox.game+xml
903914
# application/vnd.openblox.game-binary
904915
# application/vnd.openeye.oeb
@@ -1013,6 +1024,7 @@ application/vnd.pvi.ptid1 ptid
10131024
# application/vnd.pwg-multiplexed
10141025
# application/vnd.pwg-xhtml-print+xml
10151026
# application/vnd.qualcomm.brew-app-res
1027+
# application/vnd.quarantainenet
10161028
application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
10171029
# application/vnd.quobject-quoxdocument
10181030
# application/vnd.radisys.moml+xml
@@ -1032,6 +1044,7 @@ application/vnd.quark.quarkxpress qxd qxt qwd qwt qxl qxb
10321044
# application/vnd.radisys.msml-dialog-transform+xml
10331045
# application/vnd.rainstor.data
10341046
# application/vnd.rapid
1047+
# application/vnd.rar
10351048
application/vnd.realvnc.bed bed
10361049
application/vnd.recordare.musicxml mxl
10371050
application/vnd.recordare.musicxml+xml musicxml
@@ -1077,6 +1090,7 @@ application/vnd.smart.teacher teacher
10771090
application/vnd.solent.sdkm+xml sdkm sdkd
10781091
application/vnd.spotfire.dxp dxp
10791092
application/vnd.spotfire.sfs sfs
1093+
application/vnd.sqlite3 sqlite sqlite3
10801094
# application/vnd.sss-cod
10811095
# application/vnd.sss-dtf
10821096
# application/vnd.sss-ntf
@@ -1146,6 +1160,7 @@ application/vnd.uoml+xml uoml
11461160
application/vnd.vcx vcx
11471161
# application/vnd.vd-study
11481162
# application/vnd.vectorworks
1163+
# application/vnd.vel+json
11491164
# application/vnd.verimatrix.vcas
11501165
# application/vnd.vidsoft.vidconference
11511166
application/vnd.visio vsd vst vss vsw
@@ -1199,6 +1214,7 @@ application/vnd.zul zir zirz
11991214
application/vnd.zzazz.deck+xml zaz
12001215
application/voicexml+xml vxml
12011216
# application/vq-rtcpxr
1217+
application/wasm wasm
12021218
# application/watcherinfo+xml
12031219
# application/whoispp-query
12041220
# application/whoispp-response
@@ -1246,12 +1262,10 @@ application/x-font-bdf bdf
12461262
application/x-font-ghostscript gsf
12471263
# application/x-font-libgrx
12481264
application/x-font-linux-psf psf
1249-
application/x-font-otf otf
12501265
application/x-font-pcf pcf
12511266
application/x-font-snf snf
12521267
# application/x-font-speedo
12531268
# application/x-font-sunos-news
1254-
application/x-font-ttf ttf ttc
12551269
application/x-font-type1 pfa pfb pfm afm
12561270
# application/x-font-vfont
12571271
application/x-freearc arc
@@ -1428,7 +1442,7 @@ audio/mp4 m4a mp4a
14281442
audio/mpeg mpga mp2 mp2a mp3 m2a m3a
14291443
# audio/mpeg4-generic
14301444
# audio/musepack
1431-
audio/ogg oga ogg spx
1445+
audio/ogg oga ogg spx opus
14321446
# audio/opus
14331447
# audio/parityfec
14341448
# audio/pcma
@@ -1519,17 +1533,32 @@ chemical/x-cml cml
15191533
chemical/x-csml csml
15201534
# chemical/x-pdb
15211535
chemical/x-xyz xyz
1536+
font/collection ttc
1537+
font/otf otf
1538+
# font/sfnt
1539+
font/ttf ttf
1540+
font/woff woff
1541+
font/woff2 woff2
1542+
image/avif avif
15221543
image/bmp bmp
15231544
image/cgm cgm
1545+
# image/dicom-rle
1546+
# image/emf
15241547
# image/example
15251548
# image/fits
15261549
image/g3fax g3
15271550
image/gif gif
1551+
image/heic heic
1552+
image/heic-sequence heics
1553+
image/heif heif
1554+
image/heif-sequence heifs
15281555
image/ief ief
1556+
# image/jls
15291557
# image/jp2
15301558
image/jpeg jpeg jpg jpe
15311559
# image/jpm
15321560
# image/jpx
1561+
image/jxl jxl
15331562
image/ktx ktx
15341563
# image/naplps
15351564
image/png png
@@ -1572,6 +1601,7 @@ image/vnd.wap.wbmp wbmp
15721601
image/vnd.xiff xif
15731602
# image/vnd.zbrush.pcx
15741603
image/webp webp
1604+
# image/wmf
15751605
image/x-3ds 3ds
15761606
image/x-cmu-raster ras
15771607
image/x-cmx cmx
@@ -1611,6 +1641,7 @@ message/rfc822 eml mime
16111641
# message/vnd.si.simp
16121642
# message/vnd.wfa.wsc
16131643
# model/example
1644+
# model/gltf+json
16141645
model/iges igs iges
16151646
model/mesh msh mesh silo
16161647
model/vnd.collada+xml dae
@@ -1621,7 +1652,7 @@ model/vnd.gdl gdl
16211652
# model/vnd.gs.gdl
16221653
model/vnd.gtw gtw
16231654
# model/vnd.moml+xml
1624-
model/vnd.mts mts
1655+
# model/vnd.mts
16251656
# model/vnd.opengex
16261657
# model/vnd.parasolid.transmit.binary
16271658
# model/vnd.parasolid.transmit.text
@@ -1664,7 +1695,7 @@ text/csv csv
16641695
# text/fwdred
16651696
# text/grammar-ref-list
16661697
text/html html htm
1667-
# text/javascript
1698+
text/javascript js mjs
16681699
# text/jcr-cnd
16691700
# text/markdown
16701701
# text/mizar
@@ -1675,6 +1706,7 @@ text/plain txt text conf def list log in
16751706
# text/provenance-notation
16761707
# text/prs.fallenstein.rst
16771708
text/prs.lines.tag dsc
1709+
# text/prs.prop.logic
16781710
# text/raptorfec
16791711
# text/red
16801712
# text/rfc822-headers
@@ -1759,7 +1791,7 @@ video/jpm jpm jpgm
17591791
video/mj2 mj2 mjp2
17601792
# video/mp1s
17611793
# video/mp2p
1762-
# video/mp2t
1794+
video/mp2t ts m2t m2ts mts
17631795
video/mp4 mp4 mp4v mpg4
17641796
# video/mp4v-es
17651797
video/mpeg mpeg mpg mpe m1v m2v

0 commit comments

Comments
 (0)