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.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 }