in proxygen/lib/http/codec/HeaderDecodeInfo.cpp [19:129]
bool HeaderDecodeInfo::onHeader(const HPACKHeaderName& name,
const folly::fbstring& value) {
// Refuse decoding other headers if an error is already found
if (decodeError != HPACK::DecodeError::NONE || !parsingError.empty()) {
VLOG(4) << "Ignoring header=" << name << " value=" << value
<< " due to parser error=" << parsingError;
return true;
}
VLOG(5) << "Processing header=" << name << " value=" << value;
auto headerCode = name.getHeaderCode();
folly::StringPiece nameSp(name.get());
folly::StringPiece valueSp(value);
if (nameSp.startsWith(':')) {
pseudoHeaderSeen_ = true;
if (regularHeaderSeen_) {
parsingError = folly::to<string>("Illegal pseudo header name=", nameSp);
return false;
}
if (isRequest_) {
bool ok = false;
switch (headerCode) {
case HTTP_HEADER_COLON_METHOD:
ok = verifier.setMethod(valueSp);
break;
case HTTP_HEADER_COLON_SCHEME:
ok = verifier.setScheme(valueSp);
break;
case HTTP_HEADER_COLON_AUTHORITY:
ok = verifier.setAuthority(valueSp, validate_, strictValidation_);
break;
case HTTP_HEADER_COLON_PATH:
ok = verifier.setPath(valueSp, strictValidation_, allowEmptyPath_);
break;
case HTTP_HEADER_COLON_PROTOCOL:
ok = verifier.setUpgradeProtocol(valueSp, strictValidation_);
break;
default:
parsingError = folly::to<string>("Invalid req header name=", nameSp);
return false;
}
if (!ok) {
return false;
}
} else {
if (headerCode == HTTP_HEADER_COLON_STATUS) {
if (hasStatus_) {
parsingError = string("Duplicate status");
return false;
}
hasStatus_ = true;
int32_t code = -1;
folly::tryTo<int32_t>(valueSp).then(
[&code](int32_t num) { code = num; });
if (code >= 100 && code <= 999) {
msg->setStatusCode(code);
msg->setStatusMessage(HTTPMessage::getDefaultReason(code));
} else {
parsingError = folly::to<string>("Malformed status code=", valueSp);
return false;
}
} else {
parsingError = folly::to<string>("Invalid resp header name=", nameSp);
return false;
}
}
} else {
regularHeaderSeen_ = true;
switch (headerCode) {
case HTTP_HEADER_CONNECTION:
parsingError = string("HTTP/2 Message with Connection header");
return false;
case HTTP_HEADER_CONTENT_LENGTH: {
uint32_t cl = 0;
folly::tryTo<uint32_t>(valueSp).then([&cl](uint32_t num) { cl = num; });
if (contentLength_ && *contentLength_ != cl) {
parsingError = string("Multiple content-length headers");
return false;
}
contentLength_ = cl;
break;
}
default:
// no op
break;
}
bool nameOk = !validate_ || headerCode != HTTP_HEADER_OTHER ||
CodecUtil::validateHeaderName(
nameSp,
strictValidation_ ? CodecUtil::HEADER_NAME_STRICT
: CodecUtil::HEADER_NAME_STRICT_COMPAT);
bool valueOk =
!validate_ ||
CodecUtil::validateHeaderValue(
valueSp,
strictValidation_ ? CodecUtil::CtlEscapeMode::STRICT
: CodecUtil::CtlEscapeMode::STRICT_COMPAT);
if (!nameOk || !valueOk) {
parsingError = folly::to<string>("Invalid header name=", nameSp);
headerErrorValue = valueSp;
return false;
}
// Add the (name, value) pair to headers
if (headerCode == HTTP_HEADER_OTHER) {
msg->getHeaders().add(nameSp, valueSp);
} else {
msg->getHeaders().add(headerCode, valueSp);
}
}
return true;
}