1+ /*
2+ * ====================================================================
3+ * Licensed to the Apache Software Foundation (ASF) under one
4+ * or more contributor license agreements. See the NOTICE file
5+ * distributed with this work for additional information
6+ * regarding copyright ownership. The ASF licenses this file
7+ * to you under the Apache License, Version 2.0 (the
8+ * "License"); you may not use this file except in compliance
9+ * with the License. You may obtain a copy of the License at
10+ *
11+ * http://www.apache.org/licenses/LICENSE-2.0
12+ *
13+ * Unless required by applicable law or agreed to in writing,
14+ * software distributed under the License is distributed on an
15+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+ * KIND, either express or implied. See the License for the
17+ * specific language governing permissions and limitations
18+ * under the License.
19+ * ====================================================================
20+ *
21+ * This software consists of voluntary contributions made by many
22+ * individuals on behalf of the Apache Software Foundation. For more
23+ * information on the Apache Software Foundation, please see
24+ * <http://www.apache.org/>.
25+ *
26+ */
27+
28+ package org .apache .hc .client5 .http .protocol ;
29+
30+ import java .io .IOException ;
31+
32+ import org .apache .hc .core5 .annotation .Contract ;
33+ import org .apache .hc .core5 .annotation .Experimental ;
34+ import org .apache .hc .core5 .annotation .ThreadingBehavior ;
35+ import org .apache .hc .core5 .http .EntityDetails ;
36+ import org .apache .hc .core5 .http .Header ;
37+ import org .apache .hc .core5 .http .HttpException ;
38+ import org .apache .hc .core5 .http .HttpHeaders ;
39+ import org .apache .hc .core5 .http .HttpRequest ;
40+ import org .apache .hc .core5 .http .HttpRequestInterceptor ;
41+ import org .apache .hc .core5 .http .HttpVersion ;
42+ import org .apache .hc .core5 .http .ProtocolVersion ;
43+ import org .apache .hc .core5 .http .protocol .HttpContext ;
44+ import org .apache .hc .core5 .http .protocol .HttpCoreContext ;
45+ import org .apache .hc .core5 .http2 .priority .PriorityFormatter ;
46+ import org .apache .hc .core5 .http2 .priority .PriorityValue ;
47+ import org .apache .hc .core5 .util .Args ;
48+
49+ /**
50+ * Emits {@code Priority} request header for HTTP/2+.
51+ * <p>
52+ * The priority value is taken from the request context attribute
53+ * {@link #ATTR_HTTP2_PRIORITY_VALUE}. If the formatted value equals
54+ * RFC defaults (u=3, i=false) the header is omitted.
55+ * <p>
56+ * If {@code overwrite} is {@code false} (default), an existing {@code Priority}
57+ * header set by the caller is preserved.
58+ *
59+ * @since 5.6
60+ */
61+ @ Experimental
62+ @ Contract (threading = ThreadingBehavior .IMMUTABLE )
63+ public final class H2RequestPriority implements HttpRequestInterceptor {
64+
65+ /**
66+ * Context attribute to carry a {@link PriorityValue}.
67+ */
68+ public static final String ATTR_HTTP2_PRIORITY_VALUE = "http2.priority.value" ;
69+
70+ /**
71+ * Singleton with {@code overwrite=false}.
72+ */
73+ public static final H2RequestPriority INSTANCE = new H2RequestPriority (false );
74+
75+ private final boolean overwrite ;
76+
77+ public H2RequestPriority () {
78+ this (false );
79+ }
80+
81+ public H2RequestPriority (final boolean overwrite ) {
82+ this .overwrite = overwrite ;
83+ }
84+
85+ @ Override
86+ public void process (final HttpRequest request , final EntityDetails entity ,
87+ final HttpContext context ) throws HttpException , IOException {
88+
89+ Args .notNull (request , "HTTP request" );
90+ Args .notNull (context , "HTTP context" );
91+
92+ final ProtocolVersion ver = HttpCoreContext .cast (context ).getProtocolVersion ();
93+ if (ver == null || ver .compareToVersion (HttpVersion .HTTP_2 ) < 0 ) {
94+ return ; // only for HTTP/2+
95+ }
96+
97+ final Header existing = request .getFirstHeader (HttpHeaders .PRIORITY );
98+ if (existing != null && !overwrite ) {
99+ return ; // respect caller-set header
100+ }
101+
102+ final PriorityValue pv = HttpCoreContext .cast (context )
103+ .getAttribute (ATTR_HTTP2_PRIORITY_VALUE , PriorityValue .class );
104+ if (pv == null ) {
105+ return ;
106+ }
107+
108+ final String value = PriorityFormatter .format (pv );
109+ if (value == null || value .trim ().isEmpty ()) {
110+ if (overwrite && request .getFirstHeader (HttpHeaders .PRIORITY ) != null ) {
111+ request .removeHeaders (HttpHeaders .PRIORITY );
112+ }
113+ return ;
114+ }
115+
116+ if (overwrite && request .getFirstHeader (HttpHeaders .PRIORITY ) != null ) {
117+ request .removeHeaders (HttpHeaders .PRIORITY );
118+ }
119+ request .addHeader (HttpHeaders .PRIORITY , value );
120+ }
121+ }
0 commit comments