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.core5.http.message;
29  
30  import java.util.BitSet;
31  import java.util.Iterator;
32  import java.util.LinkedHashSet;
33  import java.util.Set;
34  
35  import org.apache.hc.core5.http.EntityDetails;
36  import org.apache.hc.core5.http.FormattedHeader;
37  import org.apache.hc.core5.http.Header;
38  import org.apache.hc.core5.http.HeaderElement;
39  import org.apache.hc.core5.http.HttpHeaders;
40  import org.apache.hc.core5.http.HttpMessage;
41  import org.apache.hc.core5.http.HttpResponse;
42  import org.apache.hc.core5.http.HttpStatus;
43  import org.apache.hc.core5.http.MessageHeaders;
44  import org.apache.hc.core5.http.Method;
45  import org.apache.hc.core5.util.Args;
46  import org.apache.hc.core5.util.CharArrayBuffer;
47  import org.apache.hc.core5.util.TextUtils;
48  import org.apache.hc.core5.util.Tokenizer;
49  
50  /**
51   * Support methods for HTTP message processing.
52   *
53   * @since 5.0
54   */
55  public class MessageSupport {
56  
57      /**
58       * An empty immutable {@code String} array.
59       */
60      private static final String[] EMPTY_STRING_ARRAY = new String[0];
61  
62      private MessageSupport() {
63          // Do not allow utility class to be instantiated.
64      }
65  
66      public static void formatTokens(final CharArrayBuffer dst, final String... tokens) {
67          Args.notNull(dst, "Destination");
68          for (int i = 0; i < tokens.length; i++) {
69              final String element = tokens[i];
70              if (i > 0) {
71                  dst.append(", ");
72              }
73              dst.append(element);
74          }
75      }
76  
77      public static void formatTokens(final CharArrayBuffer dst, final Set<String> tokens) {
78          Args.notNull(dst, "Destination");
79          if (tokens == null || tokens.isEmpty()) {
80              return;
81          }
82          formatTokens(dst, tokens.toArray(EMPTY_STRING_ARRAY));
83      }
84  
85      public static Header format(final String name, final Set<String> tokens) {
86          Args.notBlank(name, "Header name");
87          if (tokens == null || tokens.isEmpty()) {
88              return null;
89          }
90          final CharArrayBufferrayBuffer.html#CharArrayBuffer">CharArrayBuffer buffer = new CharArrayBuffer(256);
91          buffer.append(name);
92          buffer.append(": ");
93          formatTokens(buffer, tokens);
94          return BufferedHeader.create(buffer);
95      }
96  
97      public static Header format(final String name, final String... tokens) {
98          Args.notBlank(name, "Header name");
99          if (tokens == null || tokens.length == 0) {
100             return null;
101         }
102         final CharArrayBufferrayBuffer.html#CharArrayBuffer">CharArrayBuffer buffer = new CharArrayBuffer(256);
103         buffer.append(name);
104         buffer.append(": ");
105         formatTokens(buffer, tokens);
106         return BufferedHeader.create(buffer);
107     }
108 
109     private static final BitSet COMMA = Tokenizer.INIT_BITSET(',');
110 
111     public static Set<String> parseTokens(final CharSequence src, final ParserCursor cursor) {
112         Args.notNull(src, "Source");
113         Args.notNull(cursor, "Cursor");
114         final Set<String> tokens = new LinkedHashSet<>();
115         while (!cursor.atEnd()) {
116             final int pos = cursor.getPos();
117             if (src.charAt(pos) == ',') {
118                 cursor.updatePos(pos + 1);
119             }
120             final String token = Tokenizer.INSTANCE.parseToken(src, cursor, COMMA);
121             if (!TextUtils.isBlank(token)) {
122                 tokens.add(token);
123             }
124         }
125         return tokens;
126     }
127 
128     public static Set<String> parseTokens(final Header header) {
129         Args.notNull(header, "Header");
130         if (header instanceof FormattedHeader) {
131             final CharArrayBuffer buf = ((FormattedHeader) header).getBuffer();
132             final ParserCursorsage/ParserCursor.html#ParserCursor">ParserCursor cursor = new ParserCursor(0, buf.length());
133             cursor.updatePos(((FormattedHeader) header).getValuePos());
134             return parseTokens(buf, cursor);
135         }
136         final String value = header.getValue();
137         final ParserCursorsage/ParserCursor.html#ParserCursor">ParserCursor cursor = new ParserCursor(0, value.length());
138         return parseTokens(value, cursor);
139     }
140 
141     public static void addContentTypeHeader(final HttpMessage message, final EntityDetails entity) {
142         if (entity != null && entity.getContentType() != null && !message.containsHeader(HttpHeaders.CONTENT_TYPE)) {
143             message.addHeader(new BasicHeader(HttpHeaders.CONTENT_TYPE, entity.getContentType()));
144         }
145     }
146 
147     public static void addContentEncodingHeader(final HttpMessage message, final EntityDetails entity) {
148         if (entity != null && entity.getContentEncoding() != null && !message.containsHeader(HttpHeaders.CONTENT_ENCODING)) {
149             message.addHeader(new BasicHeader(HttpHeaders.CONTENT_ENCODING, entity.getContentEncoding()));
150         }
151     }
152 
153     public static void addTrailerHeader(final HttpMessage message, final EntityDetails entity) {
154         if (entity != null && !message.containsHeader(HttpHeaders.TRAILER)) {
155             final Set<String> trailerNames = entity.getTrailerNames();
156             if (trailerNames != null && !trailerNames.isEmpty()) {
157                 message.setHeader(MessageSupport.format(HttpHeaders.TRAILER, trailerNames));
158             }
159         }
160     }
161 
162     public static Iterator<HeaderElement> iterate(final MessageHeaders headers, final String name) {
163         Args.notNull(headers, "Message headers");
164         Args.notBlank(name, "Header name");
165         return new BasicHeaderElementIterator(headers.headerIterator(name));
166     }
167 
168     public static HeaderElement[] parse(final Header header) {
169         Args.notNull(header, "Headers");
170         final String value = header.getValue();
171         if (value == null) {
172             return new HeaderElement[] {};
173         }
174         final ParserCursorsage/ParserCursor.html#ParserCursor">ParserCursor cursor = new ParserCursor(0, value.length());
175         return BasicHeaderValueParser.INSTANCE.parseElements(value, cursor);
176     }
177 
178     /**
179      * @since  5.0
180      */
181     public static boolean canResponseHaveBody(final String method, final HttpResponse response) {
182         if (Method.HEAD.isSame(method)) {
183             return false;
184         }
185         final int status = response.getCode();
186         if (Method.CONNECT.isSame(method) && status == HttpStatus.SC_OK) {
187             return false;
188         }
189         return status >= HttpStatus.SC_SUCCESS
190                 && status != HttpStatus.SC_NO_CONTENT
191                 && status != HttpStatus.SC_NOT_MODIFIED;
192     }
193 
194 }