All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.servlet.http.HttpHeaders Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.feilong.servlet.http;

/**
 * HTTP headers相关常量.
 * 
 * 

* All headers defined in RFC 1945 (HTTP/1.0), * RFC2616 (HTTP/1.1), and * RFC2518 (WebDAV) are listed. *

* *

关于大小写:

*
* both HTTP/1.1 and HTTP/2 headers are case-insensitive. * *

* According to {@link RFC 7230 (HTTP/1.1)}: *

* * Each header field consists of a case-insensitive field name followed by a colon (":"), optional leading whitespace, the field value, and * optional trailing whitespace. * *

* Also, {@link RFC 7540 (HTTP/2)}: *

* Just as in HTTP/1.x, header field names are strings of ASCII characters that are compared in a case-insensitive fashion. * *
* * @see "org.apache.http.HttpHeaders" * @see "org.springframework.http.HttpHeaders" * @see RFC1945 * @see RFC2616 * @see RFC2518 * @see Are HTTP headers case-sensitive? * @since 1.0.8 */ public final class HttpHeaders{ /** {@value} RFC 2616 (HTTP/1.1) Section 14.1 */ public static final String ACCEPT = "Accept"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.2 */ public static final String ACCEPT_CHARSET = "Accept-Charset"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.3 */ public static final String ACCEPT_ENCODING = "Accept-Encoding"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.4 */ public static final String ACCEPT_LANGUAGE = "Accept-Language"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.5 */ public static final String ACCEPT_RANGES = "Accept-Ranges"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.6 */ public static final String AGE = "Age"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.1, RFC 2616 (HTTP/1.1) Section 14.7 */ public static final String ALLOW = "Allow"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.2, RFC 2616 (HTTP/1.1) Section 14.8 */ public static final String AUTHORIZATION = "Authorization"; /** * {@value} RFC 2616 (HTTP/1.1) Section 14.9 * * HTTP 1.1介绍了另外一组头信息属性:Cache-Control响应头信息,让网站的发布者可以更全面的控制他们的内容,并定位过期时间的限制. * *

* Cache-control值为"no-cache"时,访问此页面不会在Internet临时文章夹留下页面备份. *

* *

* 在HTTP/1.1这个标准中引入了一个新的字段Cache-control.Cache-control中有一条指令,叫max-age.
* Age表示这个Response已经存活了多久了. * 而max-age表示response最大的存活时间.所以,max-age表明了这条被cache的消息在多长时间段内是有效的. *

* *

* Example 1: {@code response.setHeader("Cache-Control", "max-age=3600");} *

* *

* 如果返回的消息中,同时出现了Cache-control: max-age和Expires,那么以Cache-control: max-age为准,Expires的声明将会被覆盖掉. *

* *

有用的 Cache-Control响应头信息包括:

* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
字段说明
max-age=[秒]执行缓存被认为是最新的最长时间.
* 类似于过期时间,这个参数是基于请求时间的相对时间间隔,而不是绝对过期时间,
* [秒]是一个数字,单位是秒:从请求时间开始到过期时间之间的秒数.
s-maxage=[秒]类似于max-age属性,除了他应用于共享(如:代理服务器)缓存
PrivateA cache mechanism may cache this page in a private cache and resend it only to a single client.
* This is the default value. Most proxy servers will not cache pages with this setting.
public标记认证内容也可以被缓存, 一般来说: 经过HTTP认证才能访问的内容,输出是自动不可以缓存的;
* Shared caches, such as proxy servers, will cache pages with this setting.
* The cached page can be sent to any user.
no-cache强制每次请求直接发送给源服务器,而不经过本地缓存版本的校验.
* 这对于需要确认认证应用很有用(可以和public结合使用),或者严格要求使用最新数据的应用(不惜牺牲使用缓存的所有好处);
* Do not cache this page, even if for use by the same client.
no-store强制缓存在任何情况下都不要保留任何副本,
* The response and the request that created it must not be stored on any cache, whether shared or private.
* The storage inferred here is nonvolatile storage, such as tape backups.
* This is not an infallible security measure.
must-revalidate告诉缓存必须遵循所有你给予副本的新鲜度的,HTTP允许缓存在某些特定情况下返回过期数据,
* 指定了这个属性,你高速缓存,你希望严格的遵循你的规则.
proxy-revalidate和 must-revalidate类似,除了他只对缓存代理服务器起作用
* * 举例: * Cache-Control: max-age=3600, must-revalidate *
* *

no-cache and no-store trigger a different behavior:

*
*

* While no-store effectively disables caching,no-cache allows the browser to cache but enforces it to always check the server for a * change. *

* *

* Quote:
* * "If the no-cache directive does not specify a field-name, then a cache MUST NOT use the response to satisfy a subsequent request * without successful revalidation with the origin server." *

* *

* This usually is the desired behavior:
* The browser sends a request every time the user navigates on a page.
* The server either sends an updated page or a 304 HTTP header, if the site did not change.
* This ensures fresh content with a minimum of traffic. *

* *
* *

* 对于 Expires 响应头我们需要注意一点,当响应头中已经设置了 Cache-Contrl:max-age 以后, max-age 将覆盖掉 expires 的效果
* (参见 http1.1 规范)原文如下:
* Note: if a response includes a Cache-Control field with the max-age directive (see section 14.9.3 ), that directive overrides the * Expires field.
* 对于 Expires 特别适合对于网站静态资源的缓存,比如 js,image,logo 等,这些资源不会经常发生变化,另外一个也适合于一些周期性更新的内容. *

* * @see #EXPIRES * @since HTTP/1.1 */ public static final String CACHE_CONTROL = "Cache-Control"; /** * {@value} RFC 2616 (HTTP/1.1) Section 14.10 */ public static final String CONNECTION = "Connection"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.3, RFC 2616 (HTTP/1.1) Section 14.11 */ public static final String CONTENT_ENCODING = "Content-Encoding"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.12 */ public static final String CONTENT_LANGUAGE = "Content-Language"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.4, RFC 2616 (HTTP/1.1) Section 14.13 */ public static final String CONTENT_LENGTH = "Content-Length"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.14 */ public static final String CONTENT_LOCATION = "Content-Location"; /** The content disposition. */ public static final String CONTENT_DISPOSITION = "Content-Disposition"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.15 */ public static final String CONTENT_MD5 = "Content-MD5"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.16 */ public static final String CONTENT_RANGE = "Content-Range"; /** * RFC 1945 (HTTP/1.0) Section 10.5, RFC 2616 (HTTP/1.1) Section 14.17 {@value}. * *
     * http://tools.ietf.org/html/rfc2616#section-7.2.1
     * 7.2.1 Type
     * 
     *    When an entity-body is included with a message, the data type of that body is determined via the header fields Content-Type and Content-Encoding. 
     *    These define a two-layer, ordered encoding model:
     * 
     *        entity-body := Content-Encoding( Content-Type( data ) )
     * 
     *    Content-Type specifies the media type of the underlying data.
     *    Content-Encoding may be used to indicate any additional content codings applied to the data, usually for the purpose of data compression, that are a property of the requested resource. There is no default encoding.
     * 
     *    Any HTTP/1.1 message containing an entity-body SHOULD include a Content-Type header field defining the media type of that body. 
     *    If and only if the media type is not given by a Content-Type field, the recipient MAY attempt to guess the media type via inspection of its
     *    content and/or the name extension(s) of the URI used to identify the resource. 
     *    If the media type remains unknown, the recipient SHOULD treat it as type "application/octet-stream".
     * 
*/ public static final String CONTENT_TYPE = "Content-Type"; /** * Date头域表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date: Mon, 20 Nov 2017 12:47:03 GMT. * *

* {@value} RFC 1945 (HTTP/1.0) Section 10.6, RFC 2616 (HTTP/1.1) Section 14.18 *

*/ public static final String DATE = "Date"; /** {@value} RFC 2518 (WevDAV) Section 9.1 */ public static final String DAV = "Dav"; /** {@value} RFC 2518 (WevDAV) Section 9.2 */ public static final String DEPTH = "Depth"; /** {@value} RFC 2518 (WevDAV) Section 9.3 */ public static final String DESTINATION = "Destination"; /** * {@value} RFC 2616 (HTTP/1.1) Section 14.19 . * *

说明:

*
*
    *
  1. * Etag 是 http 1.1 规范引入的一个新的 http 实体头, Etag 在规范中仅仅只 etag 可以用来对同一个资源的其它实体头进行对比,没有做进一步的解释,
    * 其实我们可以把 Etag 理解为一个服务器在某个资源上面做的一个记号,至于这个记号用来做什么要看服务器如何去解析它,因此我们在设计我们自己的应用的时候,可以借助 Etag 来实现客户端缓存和服务器之间的缓存协商控制. *
  2. * *
  3. * 当浏览器第一次请求一个资源的时候,服务器在响应头里面加入 Etag 的标识, Etag 的值既是当前响应内容经过计算以后的值( http 规范没有对 etag 值的计算方式做规定,可以是 md5 或者其它方式)当第二次浏览器发送请求的时候,浏览器便会用原先请求中 * Etag 响应头的值作为 if-None-Match 请求头的值,这样服务器接受到此次请求以后,根据 if-None-Match 的取值和当前的内容进行对比,
    * 如果相同则返回一个 304 not modified 响应码,这样浏览器收到 304 后就会用客户端本地 cache 来完成对本次请求的响应. *
  4. * *
*
* * @see "org.springframework.web.filter.ShallowEtagHeaderFilter" */ public static final String ETAG = "ETag"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.20 */ public static final String EXPECT = "Expect"; /** * {@value} RFC 1945 (HTTP/1.0) Section 10.7, RFC 2616 (HTTP/1.1) Section 14.21. * *

* Expires(过期时间) 属性是HTTP控制缓存的基本手段,Expires表示的是一个绝对的时刻.
* 这个属性告诉缓存器:相关副本在多长时间内是新鲜的 ,过了这个时间,缓存器就会向源服务器发送请求,检查文档是否被修改.
* 几乎所有的缓存服务器都支持Expires(过期时间)属性; *

* *

说明:

*
*
    * *
  1. * 记住:HTTP的日期时间必须是格林威治时间(GMT),而不是本地时间.其他的都会被解析成当前时间"之前",副本会过期
    * 举例: Expires: Fri, 30 Oct 1998 14:19:41 GMT *
  2. * *
  3. * * Expires表示的是一个 绝对的时刻,所以每次返回的Expires的时间极有可能都不一样. * *

    * 比如 :Example 1: response.setDateHeader("Expires", now + 3600000); *

    *
  4. * *
  5. *

    * 是由服务器指定的Response过期时间.
    * 表明在Expires这个时间点之前,返回的response都是足够新的或者说是有效的,Client无需再向Server发送请求.
    *

    * *

    * 需要注意的是,这里的Expires指示告诉Client如果这个response没有过期,没有必要再次访问.
    * 但这并不意味着response过期之前,Client不能向Server发送请求.
    * 同时,Expires也不意味在response过期以后,Client需要主动的去Server取最新的消息. *

    *
  6. * *
  7. *

    * 如果返回的消息中,同时出现了Cache-control: max-age和Expires,那么以Cache-control: max-age为准,Expires的声明将会被覆盖掉. *

    * *

    * (参见 http1.1 规范)原文如下:
    * Note: if a response includes a Cache-Control field with the max-age directive (see section 14.9.3 ), that directive overrides the * Expires field. *

    *
  8. * *
  9. * In other words 
    * Expires: 0 not always leads to immediate resource expiration,therefore should be avoided and 
    * Expires: -1 or Expires: [some valid date in the past] should be used instead. *
  10. * *
  11. * 对于 Expires 特别适合对于网站静态资源的缓存,比如 js,image,logo 等,这些资源不会经常发生变化,另外一个也适合于一些周期性更新的内容. *
  12. * *
*
* * @see #CACHE_CONTROL * @since HTTP/1.0 */ public static final String EXPIRES = "Expires"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.8, RFC 2616 (HTTP/1.1) Section 14.22 */ public static final String FROM = "From"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.23 */ public static final String HOST = "Host"; /** {@value} RFC 2518 (WevDAV) Section 9.4 */ public static final String IF = "If"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.24 */ public static final String IF_MATCH = "If-Match"; /** * {@value} * *

* RFC 1945 (HTTP/1.0) Section 10.9, RFC 2616 (HTTP/1.1) Section 14.25. *

* *

* 当用户第一次浏览一个网站的时候,服务器会在响应头中增加 Last-modified 这个 http 响应头, Last-modified 的格式如:Last-modified: Fri, 16 Mar 201 04:00:25 GMT
* 当用户第二次再请求同样的 url 的时候,浏览器会将last-modified 的值附加到 if-modified-since 这个 http 请求头中,服务器端接收到请求后,首先 check 一下 if-modified-since 头信息中的时间是否与当前 * url 对应的资源的最后修改时间一致,如果一致,则服务器返回 http 304 状态码,这样当浏览器收到 http 304 状态码了以后,就会利用本地缓存的内容来完成对本次用户操作的响应. *

*/ public static final String IF_MODIFIED_SINCE = "If-Modified-Since"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.26 */ public static final String IF_NONE_MATCH = "If-None-Match"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.27 */ public static final String IF_RANGE = "If-Range"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.28 */ public static final String IF_UNMODIFIED_SINCE = "If-Unmodified-Since"; /** * {@value} RFC 1945 (HTTP/1.0) Section 10.10, RFC 2616 (HTTP/1.1) Section 14.29 . *

* 如果没有设置 "Expires" and "Cache-Control" headers, 但是设置了 "Last-Modified" header , 浏览器就得自行判断它应该将这份资源缓存多久. *
* 有些浏览器会将其缓存一天以上. *

* *

* Google caching best practices guide 里说浏览器会根据 Last-Modified 自行推算缓存时长.
* Firefox 的推算方法是:缓存时长 = (Date - Last-Modified) / 10.
* Chrome / Safari / IE 并没有公布他们的公式或算法.
* 此类文件的缓存时长通常取决于以下因素 *

* * @see why-is-this-response-being * -cached * @see HTTP Caching in Mozilla */ public static final String LAST_MODIFIED = "Last-Modified"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.11, RFC 2616 (HTTP/1.1) Section 14.30 */ public static final String LOCATION = "Location"; /** {@value} RFC 2518 (WevDAV) Section 9.5 */ public static final String LOCK_TOKEN = "Lock-Token"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.31 */ public static final String MAX_FORWARDS = "Max-Forwards"; /** {@value} RFC 2518 (WevDAV) Section 9.6 */ public static final String OVERWRITE = "Overwrite"; /** * {@value} RFC 1945 (HTTP/1.0) Section 10.12, RFC 2616 (HTTP/1.1) Section 14.32 . * *

* 为了向后兼容 HTTP1.0 服务器,IE使用Pragma:no-cache 标题对 HTTP提供特殊支持
* 如果客户端通过安全连接 (https://)/与服务器通讯,且服务器响应中返回 Pragma:no-cache 标题,则 Internet Explorer不会缓存此响应.
*

* *

* 注意:Pragma:no-cache 仅当在安全连接中使用时才防止缓存,如果在非安全页中使用,处理方式与 Expires:-1相同,该页将被缓存,但被标记为立即过期 *

* * * Pragma头域用来包含实现特定的指令,最常用的是Pragma:no-cache.
* 在HTTP/1.1协议中,它的含义和Cache-Control:no-cache相同.. * *

* * 很多人认为在HTTP头信息中设置了Pragma: no-cache后会让内容无法被缓存.
* 但事实并非如此:HTTP的规范中,响应型头信息没有任何关于Pragma属性的说明,
* 原文如下(来自 http1.1 规范):
* Note: because the meaning of "Pragma: no-cache as a response header field is not actually specified, it does not provide a reliable * replacement for "Cache-Control: no-cache" in a response,
* 虽然少数集中缓存服务器会遵循这个头信息,但大部分不会.
*

* * @since HTTP/1.0 */ public static final String PRAGMA = "Pragma"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.33 */ public static final String PROXY_AUTHENTICATE = "Proxy-Authenticate"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.34 */ public static final String PROXY_AUTHORIZATION = "Proxy-Authorization"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.35 */ public static final String RANGE = "Range"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.13, RFC 2616 (HTTP/1.1) Section 14.36 */ public static final String REFERER = "Referer"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.37 */ public static final String RETRY_AFTER = "Retry-After"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.14, RFC 2616 (HTTP/1.1) Section 14.38 */ public static final String SERVER = "Server"; /** {@value} RFC 2518 (WevDAV) Section 9.7 */ public static final String STATUS_URI = "Status-URI"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.39 */ public static final String TE = "TE"; /** {@value} RFC 2518 (WevDAV) Section 9.8 */ public static final String TIMEOUT = "Timeout"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.40 */ public static final String TRAILER = "Trailer"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.41 */ public static final String TRANSFER_ENCODING = "Transfer-Encoding"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.42 */ public static final String UPGRADE = "Upgrade"; /** * {@value} RFC 1945 (HTTP/1.0) Section 10.15, RFC 2616 (HTTP/1.1) Section 14.43 *

* 它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等. *

* *
    *  userAgent 属性是一个只读的字符串,声明了浏览器用于 HTTP 请求的用户代理头的值.
    *  一般来讲,它是在 navigator.appCodeName 的值之后加上斜线和 navigator.appVersion 的值构成的.
    *  例如:Mozilla/4.0 (compatible; MSIE6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322).
    *  注:用户代理头:user-agent header.
    * 
    *  User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本、浏览器渲染引擎、浏览器语言、浏览器插件等.
    * 
    *  标准格式为: 
    *  浏览器标识 (操作系统标识; 加密等级标识; 浏览器语言) 渲染引擎标识 版本信息
    *  
    *  //Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17
    *  
    *  iphone :Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
     * 
     * 
* * @see 14.43 User-Agent */ public static final String USER_AGENT = "User-Agent"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.44 */ public static final String VARY = "Vary"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.45 */ public static final String VIA = "Via"; /** {@value} RFC 2616 (HTTP/1.1) Section 14.46 */ public static final String WARNING = "Warning"; /** {@value} RFC 1945 (HTTP/1.0) Section 10.16, RFC 2616 (HTTP/1.1) Section 14.47 */ public static final String WWW_AUTHENTICATE = "WWW-Authenticate"; //-------------------------header-------------------------------------- /** * 1、Origin字段里只包含是谁发起的请求,并没有其他信息 (通常情况下是方案,主机和活动文档URL的端口).
* 跟Referer不一样的是,Origin字段并没有包含涉及到用户隐私的URL路径和请求内容,这个尤其重要.
* 2、Origin字段只存在于POST请求,而Referer则存在于所有类型的请求.
* {@value} . */ public static final String ORIGIN = "origin"; //--------------------------------------------------------------- /** * X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP {@value}. * *

* 标准格式如下:
* * X-Forwarded-For: client1, proxy1, proxy2. *

* *

* 只有在通过了HTTP代理或者负载均衡服务器时才会添加该项.
*

* *

* 它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍. *

*/ public static final String X_FORWARDED_FOR = "x-forwarded-for"; /** * {@value},如果主站使用cdn的话,. * * @see Story behind * X-Forwarded-For and X-Real-IP headers * @see nginx做负载CDN加速获取端真实ip * @since 1.4.1 */ public static final String X_REAL_IP = "X-Real-IP"; /** {@value}. */ public static final String PROXY_CLIENT_IP = "Proxy-Client-IP"; /** {@value} 这个应该是WebLogic前置HttpClusterServlet提供的属性,一般不需要自己处理,在WebLogic控制台中已经可以指定使用这个属性来覆盖. */ public static final String WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP"; //--------------------------------------------------------------- /** * {@value} 用于在服务器端判断request来自Ajax请求还是传统请求. * *

* 以X打头的头域作为非HTTP标准协议,一般是某种技术的出现而产生或者某个组织指定的,
* The X-Requested-With is a non-standard HTTP header which is mainly used to identify Ajax requests.
* Most JavaScript frameworks send this header with value of XMLHttpRequest. *

* *

* 注:x-requested-with这个头是某些JS类库给加上去的,直接写AJAX是没有这个头的,
* jquery/ext 确定添加,暂时可以使用这个来判断 *

* * @see HTTP之X-Requested-With分析和思考 */ public static final String X_REQUESTED_WITH = "X-Requested-With"; /** {@value}. */ public static final String X_REQUESTED_WITH_VALUE_AJAX = "XMLHttpRequest"; /** Don't let anyone instantiate this class. */ private HttpHeaders(){ //AssertionError不是必须的. 但它可以避免不小心在类的内部调用构造器. 保证该类在任何情况下都不会被实例化. //see 《Effective Java》 2nd throw new AssertionError("No " + getClass().getName() + " instances for you!"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy