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.utils;
29
30
31 import static java.util.Base64.getEncoder;
32 import static java.util.Base64.getMimeDecoder;
33
34 import org.apache.hc.core5.annotation.Internal;
35
36 /**
37 * Provide implementations of the Base64 conversion methods from Commons Codec, delegating to the Java Base64
38 * implementation.
39 * <p>
40 * Only the features currently used by HttpClient are implemented here rather than all the features of Commons Codec.
41 * <p>
42 * Notes:
43 * <ul>
44 * <li>Commons Codec accepts null inputs, so this is also accepted here. This is not done in the Java 8 implementation</li>
45 * <li>Decoding invalid input returns an empty value. The Java 8 implementation throws an exception, which is caught here</li>
46 * <li>Commons Codec decoders accept both standard and url-safe variants of input. As this is not a requirement for
47 * HttpClient, this is NOT implemented here.
48 * </li>
49 * </ul>
50 * This class is intended as in interim convenience. Any new code should use `java.util.Base64` directly.
51 */
52 @Internal
53 public class Base64 {
54 private static final Base64 CODEC = new Base64();
55 private static final byte[] EMPTY_BYTES = new byte[0];
56
57 /**
58 * Return an instance of the Base64 codec that use the regular Base64 alphabet
59 * (as opposed to the URL-safe alphabet). Note that unlike the Commons Codec version,
60 * thus class will NOT decode characters from URL-safe alphabet.
61 */
62 public Base64() {
63 }
64
65 /**
66 * Creates a Base64 codec used for decoding and encoding in URL-unsafe mode.
67 * <p>
68 * As HttpClient never uses a non-zero length, this feature is not implemented here.
69 */
70
71 public Base64(final int lineLength) {
72 if (lineLength != 0) {
73 throw new UnsupportedOperationException("Line breaks not supported");
74 }
75 }
76
77 /**
78 * Decodes Base64 data into octets.
79 * <p>
80 * <b>Note:</b> this method does NOT accept URL-safe encodings
81 */
82 public static byte[] decodeBase64(final byte[] base64) {
83 return CODEC.decode(base64);
84 }
85
86 /**
87 * Decodes a Base64 String into octets.
88 * <p>
89 * <b>Note:</b> this method does NOT accept URL-safe encodings
90 */
91
92 public static byte[] decodeBase64(final String base64) {
93 return CODEC.decode(base64);
94 }
95
96 /**
97 * Encodes binary data using the base64 algorithm but does not chunk the output.
98 */
99
100 public static byte[] encodeBase64(final byte[] base64) {
101 return CODEC.encode(base64);
102 }
103
104 /**
105 * Encodes binary data using the base64 algorithm but does not chunk the output.
106 */
107
108 public static String encodeBase64String(final byte[] bytes) {
109 if (null == bytes) {
110 return null;
111 }
112
113 return getEncoder().encodeToString(bytes);
114 }
115
116 /**
117 * Decode Base64-encoded bytes to their original form, using specifications from this codec instance
118 */
119
120 public byte[] decode(final byte[] base64) {
121 if (null == base64) {
122 return null;
123 }
124
125 try {
126 return getMimeDecoder().decode(base64);
127 } catch (final IllegalArgumentException e) {
128 return EMPTY_BYTES;
129 }
130 }
131
132 /**
133 * Decode a Base64 String to its original form, using specifications from this codec instance
134 */
135
136 public byte[] decode(final String base64) {
137 if (null == base64) {
138 return null;
139 }
140
141 try {
142
143 // getMimeDecoder is used instead of getDecoder as it better matches the
144 // functionality of the default Commons Codec implementation (primarily more forgiving of strictly
145 // invalid inputs to decode)
146 // Code using java.util.Base64 directly should make a choice based on whether this forgiving nature is
147 // appropriate.
148
149 return getMimeDecoder().decode(base64);
150 } catch (final IllegalArgumentException e) {
151 return EMPTY_BYTES;
152 }
153 }
154
155 /**
156 * Encode bytes to their Base64 form, using specifications from this codec instance
157 */
158 public byte[] encode(final byte[] value) {
159 if (null == value) {
160 return null;
161 }
162 return getEncoder().encode(value);
163 }
164
165 }