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