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 import com.google.common.collect.ImmutableList; 25 26 import java.util.Objects; 27 28 /** 29 * Represents a list of optional {@link InformativeResponse}s and a final response control data. 30 * 31 * <p>If the response control data includes an informational status code (that is, a value between 32 * 100 and 199 inclusive), the control data is followed by a header section (encoded with known- or 33 * indeterminate- length according to the framing indicator) and another block of control data . 34 * This pattern repeats until the control data contains a final status code (200 to 599 inclusive). 35 * 36 * <p>The control data for a response message consists of the status code. The status code is 37 * encoded as a variable length integer, not a length-prefixed decimal string. 38 * 39 * @see <a 40 * href="https://www.ietf.org/archive/id/draft-ietf-httpbis-binary-message-06.html#name-response-control-data">Binary 41 * HTTP Response Control Data</a> 42 */ 43 @AutoValue 44 public abstract class ResponseControlData extends ControlData { 45 private static final int FINAL_STATUS_CODE_SECTION_COUNT = 1; 46 47 /** Returns the final status code of the response. */ getFinalStatusCode()48 public abstract int getFinalStatusCode(); 49 50 /** Returns the informative responses of the response. */ 51 @NonNull getInformativeResponses()52 public abstract ImmutableList<InformativeResponse> getInformativeResponses(); 53 54 /** 55 * {@inheritDoc} 56 * 57 * @return [[informative status code][header fields sections]*n]*n[final status code] 58 * @see Fields#knownLengthSerialize() 59 */ 60 @Override 61 @NonNull knownLengthSerialize()62 byte[][] knownLengthSerialize() { 63 int totalLength = 64 FINAL_STATUS_CODE_SECTION_COUNT 65 + getInformativeResponses().stream() 66 .mapToInt( 67 InformativeResponse::getKnownLengthSerializedSectionsCount) 68 .sum(); 69 byte[][] result = new byte[totalLength][]; 70 int pos = 0; 71 72 for (InformativeResponse informativeResponse : getInformativeResponses()) { 73 byte[][] subSections = informativeResponse.knownLengthSerialize(); 74 System.arraycopy(subSections, 0, result, pos, subSections.length); 75 pos += subSections.length; 76 } 77 78 result[pos] = toFrc9000Int(getFinalStatusCode()); 79 80 return result; 81 } 82 83 @Override getKnownLengthSerializedSectionsCount()84 int getKnownLengthSerializedSectionsCount() { 85 return getInformativeResponses().stream() 86 .mapToInt(InformativeResponse::getKnownLengthSerializedSectionsCount) 87 .sum() 88 + FINAL_STATUS_CODE_SECTION_COUNT; 89 } 90 91 /** Get a builder for response control data. */ 92 @NonNull builder()93 public static Builder builder() { 94 return new AutoValue_ResponseControlData.Builder(); 95 } 96 97 /** Builder for {@link ResponseControlData}. */ 98 @AutoValue.Builder 99 public abstract static class Builder { 100 /** Sets the final status code of the response. */ setFinalStatusCode(int value)101 public abstract Builder setFinalStatusCode(int value); 102 103 @NonNull informativeResponsesBuilder()104 abstract ImmutableList.Builder<InformativeResponse> informativeResponsesBuilder(); 105 106 /** Append an informative response to the response. */ addInformativeResponse( @onNull final InformativeResponse informativeResponse)107 public Builder addInformativeResponse( 108 @NonNull final InformativeResponse informativeResponse) { 109 informativeResponsesBuilder().add(informativeResponse); 110 return this; 111 } 112 autoBuild()113 abstract ResponseControlData autoBuild(); 114 /** Returns the response control data built. */ build()115 public ResponseControlData build() { 116 ResponseControlData responseControlData = autoBuild(); 117 Objects.requireNonNull(responseControlData.getInformativeResponses()); 118 HttpStatusCodeUtil.checkIsFinalStatusCode(responseControlData.getFinalStatusCode()); 119 return responseControlData; 120 } 121 } 122 } 123