//----------------------------------------------------------------------------- // nsHttpHeaderArray <public> //----------------------------------------------------------------------------- nsresult nsHttpHeaderArray::SetHeader(nsHttpAtom header, const nsACString &value, bool merge, nsHttpHeaderArray::HeaderVariety variety) { MOZ_ASSERT((variety == eVarietyResponse) || (variety == eVarietyRequestDefault) || (variety == eVarietyRequestOverride), "Net original headers can only be set using SetHeader_internal()."); nsEntry *entry = nullptr; int32_t index; index = LookupEntry(header, &entry); // If an empty value is passed in, then delete the header entry... // unless we are merging, in which case this function becomes a NOP. if (value.IsEmpty()) { if (!merge && entry) { if (entry->variety == eVarietyResponseNetOriginalAndResponse) { MOZ_ASSERT(variety == eVarietyResponse); entry->variety = eVarietyResponseNetOriginal; } else { mHeaders.RemoveElementAt(index); } } return NS_OK; } MOZ_ASSERT(!entry || variety != eVarietyRequestDefault, "Cannot set default entry which overrides existing entry!"); if (!entry) { return SetHeader_internal(header, value, variety); } else if (merge && !IsSingletonHeader(header)) { return MergeHeader(header, entry, value, variety); } else { // Replace the existing string with the new value if (entry->variety == eVarietyResponseNetOriginalAndResponse) { MOZ_ASSERT(variety == eVarietyResponse); entry->variety = eVarietyResponseNetOriginal; return SetHeader_internal(header, value, variety); } else { entry->value = value; entry->variety = variety; } } return NS_OK; }
nsresult nsHttpHeaderArray::SetEmptyHeader(const nsACString &headerName, HeaderVariety variety) { nsHttpAtom header = nsHttp::ResolveAtom(PromiseFlatCString(headerName).get()); if (!header) { NS_WARNING("failed to resolve atom"); return NS_ERROR_NOT_AVAILABLE; } MOZ_ASSERT((variety == eVarietyResponse) || (variety == eVarietyRequestDefault) || (variety == eVarietyRequestOverride), "Original headers can only be set using SetHeader_internal()."); nsEntry *entry = nullptr; LookupEntry(header, &entry); if (entry && entry->variety != eVarietyResponseNetOriginalAndResponse) { entry->value.Truncate(); return NS_OK; } else if (entry) { MOZ_ASSERT(variety == eVarietyResponse); entry->variety = eVarietyResponseNetOriginal; } return SetHeader_internal(header, headerName, EmptyCString(), variety); }
nsresult nsHttpHeaderArray::SetResponseHeaderFromCache(nsHttpAtom header, const nsACString &headerNameOriginal, const nsACString &value, nsHttpHeaderArray::HeaderVariety variety) { MOZ_ASSERT((variety == eVarietyResponse) || (variety == eVarietyResponseNetOriginal), "Headers from cache can only be eVarietyResponse and " "eVarietyResponseNetOriginal"); if (variety == eVarietyResponseNetOriginal) { return SetHeader_internal(header, headerNameOriginal, value, eVarietyResponseNetOriginal); } else { nsTArray<nsEntry>::index_type index = 0; do { index = mHeaders.IndexOf(header, index, nsEntry::MatchHeader()); if (index != mHeaders.NoIndex) { nsEntry &entry = mHeaders[index]; if (value.Equals(entry.value)) { MOZ_ASSERT((entry.variety == eVarietyResponseNetOriginal) || (entry.variety == eVarietyResponseNetOriginalAndResponse), "This array must contain only eVarietyResponseNetOriginal" " and eVarietyResponseNetOriginalAndRespons headers!"); entry.variety = eVarietyResponseNetOriginalAndResponse; return NS_OK; } index++; } } while (index != mHeaders.NoIndex); // If we are here, we have not found an entry so add a new one. return SetHeader_internal(header, headerNameOriginal, value, eVarietyResponse); } }
nsresult nsHttpHeaderArray::SetEmptyHeader(nsHttpAtom header, HeaderVariety variety) { MOZ_ASSERT((variety == eVarietyResponse) || (variety == eVarietyRequestDefault) || (variety == eVarietyRequestOverride), "Original headers can only be set using SetHeader_internal()."); nsEntry *entry = nullptr; LookupEntry(header, &entry); if (entry && entry->variety != eVarietyResponseNetOriginalAndResponse) { entry->value.Truncate(); return NS_OK; } else if (entry) { MOZ_ASSERT(variety == eVarietyResponse); entry->variety = eVarietyResponseNetOriginal; } return SetHeader_internal(header, EmptyCString(), variety); }
nsresult nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header, const nsACString &value, bool response) { // mHeader holds the consolidated (merged or updated) headers. // mHeader for response header will keep the original heades as well. nsEntry *entry = nullptr; LookupEntry(header, &entry); if (!entry) { if (value.IsEmpty()) { if (!gHttpHandler->KeepEmptyResponseHeadersAsEmtpyString() && !TrackEmptyHeader(header)) { LOG(("Ignoring Empty Header: %s\n", header.get())); if (response) { // Set header as original but not as response header. return SetHeader_internal(header, value, eVarietyResponseNetOriginal); } return NS_OK; // ignore empty headers by default } } HeaderVariety variety = eVarietyRequestOverride; if (response) { variety = eVarietyResponseNetOriginalAndResponse; } return SetHeader_internal(header, value, variety); } else if (!IsSingletonHeader(header)) { HeaderVariety variety = eVarietyRequestOverride; if (response) { variety = eVarietyResponse; } nsresult rv = MergeHeader(header, entry, value, variety); if (NS_FAILED(rv)) { return rv; } if (response) { rv = SetHeader_internal(header, value, eVarietyResponseNetOriginal); } return rv; } else { // Multiple instances of non-mergeable header received from network // - ignore if same value if (!entry->value.Equals(value)) { if (IsSuspectDuplicateHeader(header)) { // reply may be corrupt/hacked (ex: CLRF injection attacks) return NS_ERROR_CORRUPTED_CONTENT; } // else silently drop value: keep value from 1st header seen LOG(("Header %s silently dropped as non mergeable header\n", header.get())); } if (response) { return SetHeader_internal(header, value, eVarietyResponseNetOriginal); } } return NS_OK; }