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