xref: /aosp_15_r20/external/federated-compute/fcp/client/http/curl/curl_header_parser.cc (revision 14675a029014e728ec732f129a32e299b2da0601)
1 /*
2  * Copyright 2022 Google LLC
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 #include "fcp/client/http/curl/curl_header_parser.h"
17 
18 #include <string>
19 #include <utility>
20 
21 #include "absl/strings/match.h"
22 #include "absl/strings/str_split.h"
23 #include "fcp/base/monitoring.h"
24 #include "fcp/client/http/http_client_util.h"
25 
26 namespace fcp::client::http::curl {
27 
CurlHeaderParser()28 CurlHeaderParser::CurlHeaderParser()
29     : status_code_(-1),
30       is_last_header_line_(false),
31       use_curl_encoding_(false) {}
32 
ParseHeader(const std::string & header_string)33 void CurlHeaderParser::ParseHeader(const std::string& header_string) {
34   if (ParseAsStatus(header_string)) {
35     return;
36   }
37   if (ParseAsHeader(header_string)) {
38     return;
39   }
40   if (ParseAsLastLine(header_string)) {
41     return;
42   }
43 }
44 
ParseAsStatus(const std::string & header_string)45 bool CurlHeaderParser::ParseAsStatus(const std::string& header_string) {
46   if (!absl::StartsWith(header_string, "HTTP/")) {
47     return false;
48   }
49 
50   std::pair<std::string, std::string> split =
51       absl::StrSplit(header_string, ' ');
52   int status_code;
53   if (!absl::SimpleAtoi(split.second.substr(0, 3), &status_code)) {
54     return false;
55   }
56 
57   status_code_ = status_code;
58   // It is required that we store only the final header list. So we keep the
59   // last set of headers
60   header_list_.clear();
61   return true;
62 }
63 
ParseAsHeader(const std::string & header_string)64 bool CurlHeaderParser::ParseAsHeader(const std::string& header_string) {
65   if (!absl::StrContains(header_string, ':')) {
66     return false;
67   }
68 
69   std::pair<std::string, std::string> split =
70       absl::StrSplit(header_string, ':');
71   std::string key = split.first;
72   std::string value = std::string(absl::StripAsciiWhitespace(split.second));
73 
74   // Removes the "Content-Encoding", "Content-Length", and "Content-Length"
75   // headers from the response when the curl encoding in use because they
76   // reflect in-flight encoded values
77   if (!use_curl_encoding_ ||
78       (!absl::EqualsIgnoreCase(key, kContentEncodingHdr) &&
79        !absl::EqualsIgnoreCase(key, kContentLengthHdr) &&
80        !absl::EqualsIgnoreCase(key, kTransferEncodingHdr))) {
81     header_list_.push_back({key, value});
82   }
83   return true;
84 }
85 
ParseAsLastLine(const std::string & header_string)86 bool CurlHeaderParser::ParseAsLastLine(const std::string& header_string) {
87   // In general, it is impossible to tell when curl will reach the last
88   // header because there could another one in some special cases. In
89   // particular, it happens when curl hits a redirect status code (301).
90   // In this case, we need to proceed.
91   if (std::string(header_string) == "\r\n" &&
92       status_code_ != HttpResponseCode::kHttpMovedPermanently) {
93     is_last_header_line_ = true;
94     return true;
95   }
96 
97   return false;
98 }
99 
UseCurlEncoding()100 void CurlHeaderParser::UseCurlEncoding() { use_curl_encoding_ = true; }
101 
IsLastHeader() const102 bool CurlHeaderParser::IsLastHeader() const { return is_last_header_line_; }
103 
GetStatusCode() const104 int CurlHeaderParser::GetStatusCode() const { return status_code_; }
105 
GetHeaderList() const106 HeaderList CurlHeaderParser::GetHeaderList() const { return header_list_; }
107 
108 }  // namespace fcp::client::http::curl
109