001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.rest; 014 015import static org.apache.juneau.internal.ArrayUtils.*; 016import static org.apache.juneau.internal.StringUtils.*; 017 018import java.lang.reflect.*; 019import java.util.*; 020 021import org.apache.juneau.*; 022import org.apache.juneau.http.*; 023import org.apache.juneau.http.Date; 024import org.apache.juneau.httppart.*; 025import org.apache.juneau.internal.*; 026import org.apache.juneau.json.*; 027import org.apache.juneau.parser.*; 028 029/** 030 * Represents the headers in an HTTP request. 031 * 032 * <p> 033 * Entries are stored in a case-insensitive map. 034 * 035 * <h5 class='section'>See Also:</h5> 036 * <ul> 037 * <li class='link'><a class="doclink" href="../../../../overview-summary.html#juneau-rest-server.RequestHeaders">Overview > juneau-rest-server > RequestHeaders</a> 038 * </ul> 039 */ 040public class RequestHeaders extends TreeMap<String,String[]> { 041 private static final long serialVersionUID = 1L; 042 043 private HttpPartParser parser; 044 private BeanSession beanSession; 045 private RequestQuery queryParams; 046 047 RequestHeaders() { 048 super(String.CASE_INSENSITIVE_ORDER); 049 } 050 051 RequestHeaders parser(HttpPartParser parser) { 052 this.parser = parser; 053 return this; 054 } 055 056 RequestHeaders beanSession(BeanSession beanSession) { 057 this.beanSession = beanSession; 058 return this; 059 } 060 061 RequestHeaders setQueryParams(RequestQuery queryParams) { 062 this.queryParams = queryParams; 063 return this; 064 } 065 066 /** 067 * Adds default entries to these headers. 068 * 069 * <p> 070 * Similar to {@link #put(String, Object)} but doesn't override existing values. 071 * 072 * @param defaultEntries 073 * The default entries. 074 * <br>Can be <jk>null</jk>. 075 * @return This object (for method chaining). 076 */ 077 public RequestHeaders addDefault(Map<String,Object> defaultEntries) { 078 if (defaultEntries != null) { 079 for (Map.Entry<String,Object> e : defaultEntries.entrySet()) { 080 String key = e.getKey(); 081 Object value = e.getValue(); 082 String[] v = get(key); 083 if (v == null || v.length == 0 || StringUtils.isEmpty(v[0])) 084 put(key, asStrings(value)); 085 } 086 } 087 return this; 088 } 089 090 /** 091 * Adds a default header value on this request. 092 * 093 * <p> 094 * Similar to {@link #put(String, Object)} but doesn't override existing values. 095 * 096 * @param name 097 * The header name. 098 * @param value 099 * The header value. 100 * <br>Converted to a String using <code>toString()</code>. 101 * <br>Ignored if value is <jk>null</jk> or blank. 102 * @return This object (for method chaining). 103 */ 104 public RequestHeaders addDefault(String name, Object value) { 105 return addDefault(Collections.singletonMap(name, value)); 106 } 107 108 /** 109 * Adds a set of header values to this object. 110 * 111 * @param name The header name. 112 * @param values The header values. 113 * @return This object (for method chaining). 114 */ 115 public RequestHeaders put(String name, Enumeration<String> values) { 116 // Optimized for enumerations of one entry, the most-common case. 117 if (values.hasMoreElements()) { 118 String v = values.nextElement(); 119 String[] s = new String[]{v}; 120 while (values.hasMoreElements()) 121 s = append(s, values.nextElement()); 122 put(name, s); 123 } 124 return this; 125 } 126 127 /** 128 * Returns the specified header value as a string. 129 * 130 * <h5 class='section'>Notes:</h5> 131 * <ul class='spaced-list'> 132 * <li> 133 * If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string. 134 * </ul> 135 * 136 * @param name The header name. 137 * @return The header value, or <jk>null</jk> if it doesn't exist. 138 */ 139 public String getString(String name) { 140 String[] v = null; 141 if (queryParams != null) 142 v = queryParams.get(name); 143 if (v == null || v.length == 0) 144 v = get(name); 145 if (v == null || v.length == 0) 146 return null; 147 return v[0]; 148 } 149 150 /** 151 * Returns the specified header value as a string. 152 * 153 * <h5 class='section'>Notes:</h5> 154 * <ul class='spaced-list'> 155 * <li> 156 * If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string. 157 * </ul> 158 * 159 * @param name The HTTP header name. 160 * @param def The default value to return if the header value isn't found. 161 * @return The header value, or the default value if the header isn't present. 162 */ 163 public String getString(String name, String def) { 164 String s = getString(name); 165 return StringUtils.isEmpty(s) ? def : s; 166 } 167 168 /** 169 * Same as {@link #getString(String)} but converts the value to an integer. 170 * 171 * @param name The HTTP header name. 172 * @return The header value, or the default value if the header isn't present. 173 */ 174 public int getInt(String name) { 175 return getInt(name, 0); 176 } 177 178 /** 179 * Same as {@link #getString(String,String)} but converts the value to an integer. 180 * 181 * @param name The HTTP header name. 182 * @param def The default value to return if the header value isn't found. 183 * @return The header value, or the default value if the header isn't present. 184 */ 185 public int getInt(String name, int def) { 186 String s = getString(name); 187 return StringUtils.isEmpty(s) ? def : Integer.parseInt(s); 188 } 189 190 /** 191 * Same as {@link #getString(String)} but converts the value to a boolean. 192 * 193 * @param name The HTTP header name. 194 * @return The header value, or the default value if the header isn't present. 195 */ 196 public boolean getBoolean(String name) { 197 return getBoolean(name, false); 198 } 199 200 /** 201 * Same as {@link #getString(String,String)} but converts the value to a boolean. 202 * 203 * @param name The HTTP header name. 204 * @param def The default value to return if the header value isn't found. 205 * @return The header value, or the default value if the header isn't present. 206 */ 207 public boolean getBoolean(String name, boolean def) { 208 String s = getString(name); 209 return StringUtils.isEmpty(s) ? def : Boolean.parseBoolean(s); 210 } 211 212 /** 213 * Sets a request header value. 214 * 215 * <p> 216 * This overwrites any previous value. 217 * 218 * @param name The header name. 219 * @param value The header value. 220 */ 221 public void put(String name, Object value) { 222 super.put(name, asStrings(value)); 223 } 224 225 /** 226 * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource. 227 * 228 * <h5 class='section'>Examples:</h5> 229 * <p class='bcode'> 230 * <jc>// Parse into an integer.</jc> 231 * <jk>int</jk> myheader = req.getHeader(<js>"My-Header"</js>, <jk>int</jk>.<jk>class</jk>); 232 * 233 * <jc>// Parse a UUID.</jc> 234 * UUID myheader = req.getHeader(<js>"My-Header"</js>, UUID.<jk>class</jk>); 235 * </p> 236 * 237 * <h5 class='section'>Notes:</h5> 238 * <ul class='spaced-list'> 239 * <li> 240 * If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string. 241 * </ul> 242 * 243 * <h5 class='section'>See Also:</h5> 244 * <ul> 245 * <li class='jf'>{@link RestContext#REST_partParser} 246 * </ul> 247 * 248 * @param name The HTTP header name. 249 * @param type The class type to convert the header value to. 250 * @param <T> The class type to convert the header value to. 251 * @return The parameter value converted to the specified class type. 252 * @throws ParseException 253 */ 254 public <T> T get(String name, Class<T> type) throws ParseException { 255 return get(parser, name, null, type); 256 } 257 258 /** 259 * Same as {@link #get(String, Class)} but allows you to override the part parser used. 260 * 261 * @param parser 262 * The parser to use for parsing the string header. 263 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 264 * @param name The HTTP header name. 265 * @param type The class type to convert the header value to. 266 * @param <T> The class type to convert the header value to. 267 * @return The parameter value converted to the specified class type. 268 * @throws ParseException 269 */ 270 public <T> T get(HttpPartParser parser, String name, Class<T> type) throws ParseException { 271 return get(parser, name, null, type); 272 } 273 274 /** 275 * Same as {@link #get(String, Class)} but returns a default value if not found. 276 * 277 * @param name The HTTP header name. 278 * @param def The default value if the header was not specified or is <jk>null</jk>. 279 * @param type The class type to convert the header value to. 280 * @param <T> The class type to convert the header value to. 281 * @return The parameter value converted to the specified class type. 282 * @throws ParseException 283 */ 284 public <T> T get(String name, T def, Class<T> type) throws ParseException { 285 return get(parser, name, def, type); 286 } 287 288 /** 289 * Same as {@link #get(String, Object, Class)} but allows you to override the part parser used. 290 * 291 * @param parser 292 * The parser to use for parsing the string header. 293 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 294 * @param name The HTTP header name. 295 * @param def The default value if the header was not specified or is <jk>null</jk>. 296 * @param type The class type to convert the header value to. 297 * @param <T> The class type to convert the header value to. 298 * @return The parameter value converted to the specified class type. 299 * @throws ParseException 300 */ 301 public <T> T get(HttpPartParser parser, String name, T def, Class<T> type) throws ParseException { 302 String s = getString(name); 303 if (s == null) 304 return def; 305 if (parser == null) 306 parser = this.parser; 307 return parser.parse(HttpPartType.HEADER, s, getClassMeta(type)); 308 } 309 310 /** 311 * Returns the specified header value converted to a POJO using the {@link HttpPartParser} registered with the resource. 312 * 313 * <p> 314 * Similar to {@link #get(String,Class)} but allows for complex collections of POJOs to be created. 315 * 316 * <h5 class='section'>Examples:</h5> 317 * <p class='bcode'> 318 * <jc>// Parse into a linked-list of strings.</jc> 319 * List<String> myheader = req.getHeader(<js>"My-Header"</js>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 320 * </p> 321 * 322 * <h5 class='section'>Notes:</h5> 323 * <ul class='spaced-list'> 324 * <li> 325 * <code>Collections</code> must be followed by zero or one parameter representing the value type. 326 * <li> 327 * <code>Maps</code> must be followed by zero or two parameters representing the key and value types. 328 * <li> 329 * If {@code allowHeaderParams} init parameter is <jk>true</jk>, then first looks for {@code &HeaderName=x} in the URL query string. 330 * </ul> 331 * 332 * <h5 class='section'>See Also:</h5> 333 * <ul> 334 * <li class='jf'>{@link RestContext#REST_partParser} 335 * </ul> 336 * 337 * @param name The HTTP header name. 338 * @param type 339 * The type of object to create. 340 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 341 * @param args 342 * The type arguments of the class if it's a collection or map. 343 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 344 * <br>Ignored if the main type is not a map or collection. 345 * @param <T> The class type to convert the header value to. 346 * @return The parameter value converted to the specified class type. 347 * @throws ParseException If the header could not be converted to the specified type. 348 */ 349 public <T> T get(String name, Type type, Type...args) throws ParseException { 350 return get(null, name, type, args); 351 } 352 353 /** 354 * Same as {@link #get(String, Type, Type...)} but allows you to override the part parser used. 355 * 356 * @param parser 357 * The parser to use for parsing the string header. 358 * <br>If <jk>null</jk>, uses the part parser defined on the resource/method. 359 * @param name 360 * The HTTP header name. 361 * @param type 362 * The type of object to create. 363 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 364 * @param args 365 * The type arguments of the class if it's a collection or map. 366 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 367 * <br>Ignored if the main type is not a map or collection. 368 * @param <T> The class type to convert the header value to. 369 * @return The parameter value converted to the specified class type. 370 * @throws ParseException If the header could not be converted to the specified type. 371 */ 372 @SuppressWarnings("unchecked") 373 public <T> T get(HttpPartParser parser, String name, Type type, Type...args) throws ParseException { 374 String s = getString(name); 375 if (s == null) 376 return null; 377 if (parser == null) 378 parser = this.parser; 379 return (T)parser.parse(HttpPartType.HEADER, s, getClassMeta(type, args)); 380 } 381 382 /** 383 * Returns a copy of this object but only with the specified header names copied. 384 * 385 * @param headers The headers to include in the copy. 386 * @return A new headers object. 387 */ 388 public RequestHeaders subset(String...headers) { 389 RequestHeaders rh2 = new RequestHeaders().parser(parser).beanSession(beanSession).setQueryParams(queryParams); 390 for (String h : headers) 391 if (containsKey(h)) 392 rh2.put(h, get(h)); 393 return rh2; 394 } 395 396 /** 397 * Same as {@link #subset(String...)} but allows you to specify header names as a comma-delimited list. 398 * 399 * @param headers The headers to include in the copy. 400 * @return A new headers object. 401 */ 402 public RequestHeaders subset(String headers) { 403 return subset(split(headers)); 404 } 405 406 /** 407 * Returns the <code>Accept</code> header on the request. 408 * 409 * <p> 410 * Content-Types that are acceptable for the response. 411 * 412 * <h5 class='figure'>Example:</h5> 413 * <p class='bcode'> 414 * Accept: text/plain 415 * </p> 416 * 417 * @return The parsed <code>Accept</code> header on the request, or <jk>null</jk> if not found. 418 */ 419 public Accept getAccept() { 420 return Accept.forString(getString("Accept")); 421 } 422 423 /** 424 * Returns the <code>Accept-Charset</code> header on the request. 425 * 426 * <p> 427 * Character sets that are acceptable. 428 * 429 * <h5 class='figure'>Example:</h5> 430 * <p class='bcode'> 431 * Accept-Charset: utf-8 432 * </p> 433 * 434 * @return The parsed <code>Accept-Charset</code> header on the request, or <jk>null</jk> if not found. 435 */ 436 public AcceptCharset getAcceptCharset() { 437 return AcceptCharset.forString(getString("Accept-Charset")); 438 } 439 440 /** 441 * Returns the <code>Accept-Encoding</code> header on the request. 442 * 443 * <p> 444 * List of acceptable encodings. 445 * 446 * <h5 class='figure'>Example:</h5> 447 * <p class='bcode'> 448 * Accept-Encoding: gzip, deflate 449 * </p> 450 * 451 * @return The parsed <code>Accept-Encoding</code> header on the request, or <jk>null</jk> if not found. 452 */ 453 public AcceptEncoding getAcceptEncoding() { 454 return AcceptEncoding.forString(getString("Accept-Encoding")); 455 } 456 457 /** 458 * Returns the <code>Accept-Language</code> header on the request. 459 * 460 * <p> 461 * List of acceptable human languages for response. 462 * 463 * <h5 class='figure'>Example:</h5> 464 * <p class='bcode'> 465 * Accept-Language: en-US 466 * </p> 467 * 468 * @return The parsed <code>Accept-Language</code> header on the request, or <jk>null</jk> if not found. 469 */ 470 public AcceptLanguage getAcceptLanguage() { 471 return AcceptLanguage.forString(getString("Accept-Language")); 472 } 473 474 /** 475 * Returns the <code>Authorization</code> header on the request. 476 * 477 * <p> 478 * Authentication credentials for HTTP authentication. 479 * 480 * <h5 class='figure'>Example:</h5> 481 * <p class='bcode'> 482 * Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== 483 * </p> 484 * 485 * @return The parsed <code>Authorization</code> header on the request, or <jk>null</jk> if not found. 486 */ 487 public Authorization getAuthorization() { 488 return Authorization.forString(getString("Authorization")); 489 } 490 491 /** 492 * Returns the <code>Cache-Control</code> header on the request. 493 * 494 * <p> 495 * Used to specify directives that must be obeyed by all caching mechanisms along the request-response chain. 496 * 497 * <h5 class='figure'>Example:</h5> 498 * <p class='bcode'> 499 * Cache-Control: no-cache 500 * </p> 501 * 502 * @return The parsed <code>Cache-Control</code> header on the request, or <jk>null</jk> if not found. 503 */ 504 public CacheControl getCacheControl() { 505 return CacheControl.forString(getString("Cache-Control")); 506 } 507 508 /** 509 * Returns the <code>Connection</code> header on the request. 510 * 511 * <p> 512 * Control options for the current connection and list of hop-by-hop request fields. 513 * 514 * <h5 class='figure'>Example:</h5> 515 * <p class='bcode'> 516 * Connection: keep-alive 517 * Connection: Upgrade 518 * </p> 519 * 520 * @return The parsed <code></code> header on the request, or <jk>null</jk> if not found. 521 */ 522 public Connection getConnection() { 523 return Connection.forString(getString("Connection")); 524 } 525 526 /** 527 * Returns the <code>Content-Length</code> header on the request. 528 * 529 * <p> 530 * The length of the request body in octets (8-bit bytes). 531 * 532 * <h5 class='figure'>Example:</h5> 533 * <p class='bcode'> 534 * Content-Length: 348 535 * </p> 536 * 537 * @return The parsed <code>Content-Length</code> header on the request, or <jk>null</jk> if not found. 538 */ 539 public ContentLength getContentLength() { 540 return ContentLength.forString(getString("Content-Length")); 541 } 542 543 /** 544 * Returns the <code>Content-Type</code> header on the request. 545 * 546 * <p> 547 * The MIME type of the body of the request (used with POST and PUT requests). 548 * 549 * <h5 class='figure'>Example:</h5> 550 * <p class='bcode'> 551 * Content-Type: application/x-www-form-urlencoded 552 * </p> 553 * 554 * @return The parsed <code>Content-Type</code> header on the request, or <jk>null</jk> if not found. 555 */ 556 public ContentType getContentType() { 557 return ContentType.forString(getString("Content-Type")); 558 } 559 560 /** 561 * Returns the <code>Date</code> header on the request. 562 * 563 * <p> 564 * The date and time that the message was originated (in "HTTP-date" format as defined by RFC 7231 Date/Time Formats). 565 * 566 * <h5 class='figure'>Example:</h5> 567 * <p class='bcode'> 568 * Date: Tue, 15 Nov 1994 08:12:31 GMT 569 * </p> 570 * 571 * @return The parsed <code>Date</code> header on the request, or <jk>null</jk> if not found. 572 */ 573 public Date getDate() { 574 return Date.forString(getString("Date")); 575 } 576 577 /** 578 * Returns the <code>Expect</code> header on the request. 579 * 580 * <p> 581 * Indicates that particular server behaviors are required by the client. 582 * 583 * <h5 class='figure'>Example:</h5> 584 * <p class='bcode'> 585 * Expect: 100-continue 586 * </p> 587 * 588 * @return The parsed <code>Expect</code> header on the request, or <jk>null</jk> if not found. 589 */ 590 public Expect getExpect() { 591 return Expect.forString(getString("Expect")); 592 } 593 594 /** 595 * Returns the <code>From</code> header on the request. 596 * 597 * <p> 598 * The email address of the user making the request. 599 * 600 * <h5 class='figure'>Example:</h5> 601 * <p class='bcode'> 602 * From: user@example.com 603 * </p> 604 * 605 * @return The parsed <code>From</code> header on the request, or <jk>null</jk> if not found. 606 */ 607 public From getFrom() { 608 return From.forString(getString("From")); 609 } 610 611 /** 612 * Returns the <code>Host</code> header on the request. 613 * 614 * <p> 615 * The domain name of the server (for virtual hosting), and the TCP port number on which the server is listening. 616 * The port number may be omitted if the port is the standard port for the service requested. 617 * 618 * <h5 class='figure'>Example:</h5> 619 * <p class='bcode'> 620 * Host: en.wikipedia.org:8080 621 * Host: en.wikipedia.org 622 * </p> 623 * 624 * @return The parsed <code>Host</code> header on the request, or <jk>null</jk> if not found. 625 */ 626 public Host getHost() { 627 return Host.forString(getString("Host")); 628 } 629 630 /** 631 * Returns the <code>If-Match</code> header on the request. 632 * 633 * <p> 634 * Only perform the action if the client supplied entity matches the same entity on the server. 635 * This is mainly for methods like PUT to only update a resource if it has not been modified since the user last 636 * updated it. 637 * 638 * <h5 class='figure'>Example:</h5> 639 * <p class='bcode'> 640 * If-Match: "737060cd8c284d8af7ad3082f209582d" 641 * </p> 642 * 643 * @return The parsed <code>If-Match</code> header on the request, or <jk>null</jk> if not found. 644 */ 645 public IfMatch getIfMatch() { 646 return IfMatch.forString(getString("If-Match")); 647 } 648 649 /** 650 * Returns the <code>If-Modified-Since</code> header on the request. 651 * 652 * <p> 653 * Allows a 304 Not Modified to be returned if content is unchanged. 654 * 655 * <h5 class='figure'>Example:</h5> 656 * <p class='bcode'> 657 * If-Modified-Since: Sat, 29 Oct 1994 19:43:31 GMT 658 * </p> 659 * 660 * @return The parsed <code>If-Modified-Since</code> header on the request, or <jk>null</jk> if not found. 661 */ 662 public IfModifiedSince getIfModifiedSince() { 663 return IfModifiedSince.forString(getString("If-Modified-Since")); 664 } 665 666 /** 667 * Returns the <code>If-None-Match</code> header on the request. 668 * 669 * <p> 670 * Allows a 304 Not Modified to be returned if content is unchanged, see HTTP ETag. 671 * 672 * <h5 class='figure'>Example:</h5> 673 * <p class='bcode'> 674 * If-None-Match: "737060cd8c284d8af7ad3082f209582d" 675 * </p> 676 * 677 * @return The parsed <code>If-None-Match</code> header on the request, or <jk>null</jk> if not found. 678 */ 679 public IfNoneMatch getIfNoneMatch() { 680 return IfNoneMatch.forString(getString("If-None-Match")); 681 } 682 683 /** 684 * Returns the <code>If-Range</code> header on the request. 685 * 686 * <p> 687 * If the entity is unchanged, send me the part(s) that I am missing; otherwise, send me the entire new entity. 688 * 689 * <h5 class='figure'>Example:</h5> 690 * <p class='bcode'> 691 * If-Range: "737060cd8c284d8af7ad3082f209582d" 692 * </p> 693 * 694 * @return The parsed <code>If-Range</code> header on the request, or <jk>null</jk> if not found. 695 */ 696 public IfRange getIfRange() { 697 return IfRange.forString(getString("If-Range")); 698 } 699 700 /** 701 * Returns the <code>If-Unmodified-Since</code> header on the request. 702 * 703 * <p> 704 * Only send the response if the entity has not been modified since a specific time. 705 * 706 * <h5 class='figure'>Example:</h5> 707 * <p class='bcode'> 708 * If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT 709 * </p> 710 * 711 * @return The parsed <code>If-Unmodified-Since</code> header on the request, or <jk>null</jk> if not found. 712 */ 713 public IfUnmodifiedSince getIfUnmodifiedSince() { 714 return IfUnmodifiedSince.forString(getString("If-Unmodified-Since")); 715 } 716 717 /** 718 * Returns the <code>Max-Forwards</code> header on the request. 719 * 720 * <p> 721 * Limit the number of times the message can be forwarded through proxies or gateways. 722 * 723 * <h5 class='figure'>Example:</h5> 724 * <p class='bcode'> 725 * Max-Forwards: 10 726 * </p> 727 * 728 * @return The parsed <code>Max-Forwards</code> header on the request, or <jk>null</jk> if not found. 729 */ 730 public MaxForwards getMaxForwards() { 731 return MaxForwards.forString(getString("Max-Forwards")); 732 } 733 734 /** 735 * Returns the <code>Pragma</code> header on the request. 736 * 737 * <p> 738 * Implementation-specific fields that may have various effects anywhere along the request-response chain. 739 * 740 * <h5 class='figure'>Example:</h5> 741 * <p class='bcode'> 742 * Pragma: no-cache 743 * </p> 744 * 745 * @return The parsed <code>Pragma</code> header on the request, or <jk>null</jk> if not found. 746 */ 747 public Pragma getPragma() { 748 return Pragma.forString(getString("Pragma")); 749 } 750 751 /** 752 * Returns the <code>Proxy-Authorization</code> header on the request. 753 * 754 * <p> 755 * Authorization credentials for connecting to a proxy. 756 * 757 * <h5 class='figure'>Example:</h5> 758 * <p class='bcode'> 759 * Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== 760 * </p> 761 * 762 * @return The parsed <code>Proxy-Authorization</code> header on the request, or <jk>null</jk> if not found. 763 */ 764 public ProxyAuthorization getProxyAuthorization() { 765 return ProxyAuthorization.forString(getString("Proxy-Authorization")); 766 } 767 768 /** 769 * Returns the <code>Range</code> header on the request. 770 * 771 * <p> 772 * Request only part of an entity. Bytes are numbered from 0. 773 * 774 * <h5 class='figure'>Example:</h5> 775 * <p class='bcode'> 776 * Range: bytes=500-999 777 * </p> 778 * 779 * @return The parsed <code>Range</code> header on the request, or <jk>null</jk> if not found. 780 */ 781 public Range getRange() { 782 return Range.forString(getString("Range")); 783 } 784 785 /** 786 * Returns the <code>Referer</code> header on the request. 787 * 788 * <p> 789 * This is the address of the previous web page from which a link to the currently requested page was followed. 790 * 791 * <h5 class='figure'>Example:</h5> 792 * <p class='bcode'> 793 * Referer: http://en.wikipedia.org/wiki/Main_Page 794 * </p> 795 * 796 * @return The parsed <code>Referer</code> header on the request, or <jk>null</jk> if not found. 797 */ 798 public Referer getReferer() { 799 return Referer.forString(getString("Referer")); 800 } 801 802 /** 803 * Returns the <code>TE</code> header on the request. 804 * 805 * <p> 806 * The transfer encodings the user agent is willing to accept: the same values as for the response header field 807 * Transfer-Encoding can be used, plus the "trailers" value (related to the "chunked" transfer method) to notify the 808 * server it expects to receive additional fields in the trailer after the last, zero-sized, chunk. 809 * 810 * <h5 class='figure'>Example:</h5> 811 * <p class='bcode'> 812 * TE: trailers, deflate 813 * </p> 814 * 815 * @return The parsed <code>TE</code> header on the request, or <jk>null</jk> if not found. 816 */ 817 public TE getTE() { 818 return TE.forString(getString("TE")); 819 } 820 821 /** 822 * Returns the <code>Time-Zone</code> header value on the request if there is one. 823 * 824 * <p> 825 * Example: <js>"GMT"</js>. 826 * 827 * @return The <code>Time-Zone</code> header value on the request, or <jk>null</jk> if not present. 828 */ 829 public TimeZone getTimeZone() { 830 String tz = getString("Time-Zone"); 831 if (tz != null) 832 return TimeZone.getTimeZone(tz); 833 return null; 834 } 835 836 /** 837 * Returns the <code>User-Agent</code> header on the request. 838 * 839 * <p> 840 * The user agent string of the user agent. 841 * 842 * <h5 class='figure'>Example:</h5> 843 * <p class='bcode'> 844 * User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0 845 * </p> 846 * 847 * @return The parsed <code>User-Agent</code> header on the request, or <jk>null</jk> if not found. 848 */ 849 public UserAgent getUserAgent() { 850 return UserAgent.forString(getString("User-Agent")); 851 } 852 853 /** 854 * Returns the <code>Upgrade</code> header on the request. 855 * 856 * <p> 857 * Ask the server to upgrade to another protocol. 858 * 859 * <h5 class='figure'>Example:</h5> 860 * <p class='bcode'> 861 * Upgrade: HTTP/2.0, HTTPS/1.3, IRC/6.9, RTA/x11, websocket 862 * </p> 863 * 864 * @return The parsed <code>Upgrade</code> header on the request, or <jk>null</jk> if not found. 865 */ 866 public Upgrade getUpgrade() { 867 return Upgrade.forString(getString("Upgrade")); 868 } 869 870 /** 871 * Returns the <code>Via</code> header on the request. 872 * 873 * <p> 874 * Informs the server of proxies through which the request was sent. 875 * 876 * <h5 class='figure'>Example:</h5> 877 * <p class='bcode'> 878 * Via: 1.0 fred, 1.1 example.com (Apache/1.1) 879 * </p> 880 * 881 * @return The parsed <code>Via</code> header on the request, or <jk>null</jk> if not found. 882 */ 883 public Via getVia() { 884 return Via.forString(getString("Via")); 885 } 886 887 /** 888 * Returns the <code>Warning</code> header on the request. 889 * 890 * <p> 891 * A general warning about possible problems with the entity body. 892 * 893 * <h5 class='figure'>Example:</h5> 894 * <p class='bcode'> 895 * Warning: 199 Miscellaneous warning 896 * </p> 897 * 898 * @return The parsed <code>Warning</code> header on the request, or <jk>null</jk> if not found. 899 */ 900 public Warning getWarning() { 901 return Warning.forString(getString("Warning")); 902 } 903 904 /** 905 * Converts the headers to a readable string. 906 * 907 * @param sorted Sort the headers by name. 908 * @return A JSON string containing the contents of the headers. 909 */ 910 public String toString(boolean sorted) { 911 Map<String,Object> m = (sorted ? new TreeMap<String,Object>() : new LinkedHashMap<String,Object>()); 912 for (Map.Entry<String,String[]> e : this.entrySet()) { 913 String[] v = e.getValue(); 914 m.put(e.getKey(), v.length == 1 ? v[0] : v); 915 } 916 return JsonSerializer.DEFAULT_LAX.toString(m); 917 } 918 919 private ClassMeta<?> getClassMeta(Type type, Type...args) { 920 return beanSession.getClassMeta(type, args); 921 } 922 923 private <T> ClassMeta<T> getClassMeta(Class<T> type) { 924 return beanSession.getClassMeta(type); 925 } 926 927 @Override /* Object */ 928 public String toString() { 929 return toString(false); 930 } 931}