1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adservices.service.common.bhttp;
18 
19 import static com.android.adservices.service.common.bhttp.Frc9000VariableLengthIntegerUtil.toFrc9000Int;
20 
21 import android.annotation.NonNull;
22 
23 import com.google.auto.value.AutoValue;
24 
25 /**
26  * Responses that include informational status codes (see Section 15.2 of [HTTP]) are encoded by
27  * repeating the response control data and associated header section until a final response control
28  * data is encoded. The status code distinguishes between informational and final responses.
29  *
30  * <p>If the response control data includes an informational status code (that is, a value between
31  * 100 and 199 inclusive), the control data is followed by a header section (encoded with known- or
32  * indeterminate- length according to the framing indicator) and another block of control data. This
33  * pattern repeats until the control data contains a final status code (200 to 599 inclusive).
34  *
35  * @see <a
36  *     href="https://www.ietf.org/archive/id/draft-ietf-httpbis-binary-message-06.html#name-informational-status-codes">Informational
37  *     Status Codes</a>}
38  */
39 @AutoValue
40 public abstract class InformativeResponse extends BinaryHttpSerializableComponent {
41     private static final int STATUS_CODE_SECTION_COUNT = 1;
42 
43     /** Returns the informative status code. */
getInformativeStatusCode()44     public abstract int getInformativeStatusCode();
45 
46     /** Returns the header fields of the informative response. */
47     @NonNull
getHeaderFields()48     public abstract Fields getHeaderFields();
49 
50     /**
51      * {@inheritDoc}
52      *
53      * @return [informative status code][header fields sections]*n
54      */
55     @NonNull
56     @Override
knownLengthSerialize()57     byte[][] knownLengthSerialize() {
58         byte[][] result = new byte[getKnownLengthSerializedSectionsCount()][];
59         result[0] = toFrc9000Int(getInformativeStatusCode());
60         byte[][] header = getHeaderFields().knownLengthSerialize();
61         System.arraycopy(header, 0, result, STATUS_CODE_SECTION_COUNT, header.length);
62         return result;
63     }
64 
65     @Override
getKnownLengthSerializedSectionsCount()66     int getKnownLengthSerializedSectionsCount() {
67         return STATUS_CODE_SECTION_COUNT
68                 + getHeaderFields().getKnownLengthSerializedSectionsCount();
69     }
70 
71     /** Get a builder for informative response. */
72     @NonNull
builder()73     public static Builder builder() {
74         return new AutoValue_InformativeResponse.Builder();
75     }
76 
77     /** Builder for {@link InformativeResponse}. */
78     @AutoValue.Builder
79     public abstract static class Builder {
80         /** Sets the informative status code. */
81         @NonNull
setInformativeStatusCode(int value)82         public abstract Builder setInformativeStatusCode(int value);
83 
84         @NonNull
headerFieldsBuilder()85         abstract Fields.Builder headerFieldsBuilder();
86 
87         /** Append the header fields of the informative response. */
88         @NonNull
appendHeaderField(@onNull final String name, @NonNull final String value)89         public Builder appendHeaderField(@NonNull final String name, @NonNull final String value) {
90             headerFieldsBuilder().appendField(name, value);
91             return this;
92         }
93 
94         /**
95          * This should only be used in {@link
96          * BinaryHttpMessageDeserializer#deserializeKnownLengthResponseControlData
97          * (BinaryHttpMessageDeserializer.BinaryHttpByteArrayReader)}.
98          *
99          * <p>Calling this method after {@link #appendHeaderField(String, String)} will result in
100          * unchecked exception.
101          */
102         @NonNull
setHeaderFields(@onNull final Fields fields)103         Builder setHeaderFields(@NonNull final Fields fields) {
104             headerFieldsBuilder().setFields(fields.getFields());
105             return this;
106         }
107 
108         @NonNull
autoBuild()109         abstract InformativeResponse autoBuild();
110 
111         /** Returns the informative response built. */
112         @NonNull
build()113         public InformativeResponse build() {
114             InformativeResponse informativeResponse = autoBuild();
115             HttpStatusCodeUtil.checkIsInformativeStatusCode(
116                     informativeResponse.getInformativeStatusCode());
117             return informativeResponse;
118         }
119     }
120 }
121