1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/http/nsHttpHeaderArray.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,220 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim:set ts=4 sw=4 sts=4 ci et: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +// HttpLog.h should generally be included first 1.11 +#include "HttpLog.h" 1.12 + 1.13 +#include "nsHttpHeaderArray.h" 1.14 +#include "nsURLHelper.h" 1.15 +#include "nsIHttpHeaderVisitor.h" 1.16 + 1.17 +namespace mozilla { 1.18 +namespace net { 1.19 + 1.20 +//----------------------------------------------------------------------------- 1.21 +// nsHttpHeaderArray <public> 1.22 +//----------------------------------------------------------------------------- 1.23 +nsresult 1.24 +nsHttpHeaderArray::SetHeader(nsHttpAtom header, 1.25 + const nsACString &value, 1.26 + bool merge) 1.27 +{ 1.28 + nsEntry *entry = nullptr; 1.29 + int32_t index; 1.30 + 1.31 + index = LookupEntry(header, &entry); 1.32 + 1.33 + // If an empty value is passed in, then delete the header entry... 1.34 + // unless we are merging, in which case this function becomes a NOP. 1.35 + if (value.IsEmpty()) { 1.36 + if (!merge && entry) 1.37 + mHeaders.RemoveElementAt(index); 1.38 + return NS_OK; 1.39 + } 1.40 + 1.41 + if (!entry) { 1.42 + entry = mHeaders.AppendElement(); // new nsEntry() 1.43 + if (!entry) 1.44 + return NS_ERROR_OUT_OF_MEMORY; 1.45 + entry->header = header; 1.46 + entry->value = value; 1.47 + } else if (merge && !IsSingletonHeader(header)) { 1.48 + MergeHeader(header, entry, value); 1.49 + } else { 1.50 + // Replace the existing string with the new value 1.51 + entry->value = value; 1.52 + } 1.53 + 1.54 + return NS_OK; 1.55 +} 1.56 + 1.57 +nsresult 1.58 +nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header, const nsACString &value) 1.59 +{ 1.60 + nsEntry *entry = nullptr; 1.61 + 1.62 + LookupEntry(header, &entry); 1.63 + 1.64 + if (!entry) { 1.65 + if (value.IsEmpty()) { 1.66 + if (!TrackEmptyHeader(header)) { 1.67 + LOG(("Ignoring Empty Header: %s\n", header.get())); 1.68 + return NS_OK; // ignore empty headers by default 1.69 + } 1.70 + } 1.71 + entry = mHeaders.AppendElement(); //new nsEntry(header, value); 1.72 + if (!entry) 1.73 + return NS_ERROR_OUT_OF_MEMORY; 1.74 + entry->header = header; 1.75 + entry->value = value; 1.76 + } else if (!IsSingletonHeader(header)) { 1.77 + MergeHeader(header, entry, value); 1.78 + } else { 1.79 + // Multiple instances of non-mergeable header received from network 1.80 + // - ignore if same value 1.81 + if (!entry->value.Equals(value)) { 1.82 + if (IsSuspectDuplicateHeader(header)) { 1.83 + // reply may be corrupt/hacked (ex: CLRF injection attacks) 1.84 + return NS_ERROR_CORRUPTED_CONTENT; 1.85 + } // else silently drop value: keep value from 1st header seen 1.86 + LOG(("Header %s silently dropped as non mergeable header\n", 1.87 + header.get())); 1.88 + } 1.89 + } 1.90 + 1.91 + return NS_OK; 1.92 +} 1.93 + 1.94 +void 1.95 +nsHttpHeaderArray::ClearHeader(nsHttpAtom header) 1.96 +{ 1.97 + mHeaders.RemoveElement(header, nsEntry::MatchHeader()); 1.98 +} 1.99 + 1.100 +const char * 1.101 +nsHttpHeaderArray::PeekHeader(nsHttpAtom header) const 1.102 +{ 1.103 + const nsEntry *entry = nullptr; 1.104 + LookupEntry(header, &entry); 1.105 + return entry ? entry->value.get() : nullptr; 1.106 +} 1.107 + 1.108 +nsresult 1.109 +nsHttpHeaderArray::GetHeader(nsHttpAtom header, nsACString &result) const 1.110 +{ 1.111 + const nsEntry *entry = nullptr; 1.112 + LookupEntry(header, &entry); 1.113 + if (!entry) 1.114 + return NS_ERROR_NOT_AVAILABLE; 1.115 + result = entry->value; 1.116 + return NS_OK; 1.117 +} 1.118 + 1.119 +nsresult 1.120 +nsHttpHeaderArray::VisitHeaders(nsIHttpHeaderVisitor *visitor) 1.121 +{ 1.122 + NS_ENSURE_ARG_POINTER(visitor); 1.123 + uint32_t i, count = mHeaders.Length(); 1.124 + for (i = 0; i < count; ++i) { 1.125 + const nsEntry &entry = mHeaders[i]; 1.126 + if (NS_FAILED(visitor->VisitHeader(nsDependentCString(entry.header), 1.127 + entry.value))) 1.128 + break; 1.129 + } 1.130 + return NS_OK; 1.131 +} 1.132 + 1.133 +nsresult 1.134 +nsHttpHeaderArray::ParseHeaderLine(const char *line, 1.135 + nsHttpAtom *hdr, 1.136 + char **val) 1.137 +{ 1.138 + // 1.139 + // BNF from section 4.2 of RFC 2616: 1.140 + // 1.141 + // message-header = field-name ":" [ field-value ] 1.142 + // field-name = token 1.143 + // field-value = *( field-content | LWS ) 1.144 + // field-content = <the OCTETs making up the field-value 1.145 + // and consisting of either *TEXT or combinations 1.146 + // of token, separators, and quoted-string> 1.147 + // 1.148 + 1.149 + // We skip over mal-formed headers in the hope that we'll still be able to 1.150 + // do something useful with the response. 1.151 + 1.152 + char *p = (char *) strchr(line, ':'); 1.153 + if (!p) { 1.154 + LOG(("malformed header [%s]: no colon\n", line)); 1.155 + return NS_OK; 1.156 + } 1.157 + 1.158 + // make sure we have a valid token for the field-name 1.159 + if (!nsHttp::IsValidToken(line, p)) { 1.160 + LOG(("malformed header [%s]: field-name not a token\n", line)); 1.161 + return NS_OK; 1.162 + } 1.163 + 1.164 + *p = 0; // null terminate field-name 1.165 + 1.166 + nsHttpAtom atom = nsHttp::ResolveAtom(line); 1.167 + if (!atom) { 1.168 + LOG(("failed to resolve atom [%s]\n", line)); 1.169 + return NS_OK; 1.170 + } 1.171 + 1.172 + // skip over whitespace 1.173 + p = net_FindCharNotInSet(++p, HTTP_LWS); 1.174 + 1.175 + // trim trailing whitespace - bug 86608 1.176 + char *p2 = net_RFindCharNotInSet(p, HTTP_LWS); 1.177 + 1.178 + *++p2 = 0; // null terminate header value; if all chars starting at |p| 1.179 + // consisted of LWS, then p2 would have pointed at |p-1|, so 1.180 + // the prefix increment is always valid. 1.181 + 1.182 + // assign return values 1.183 + if (hdr) *hdr = atom; 1.184 + if (val) *val = p; 1.185 + 1.186 + // assign response header 1.187 + return SetHeaderFromNet(atom, nsDependentCString(p, p2 - p)); 1.188 +} 1.189 + 1.190 +void 1.191 +nsHttpHeaderArray::Flatten(nsACString &buf, bool pruneProxyHeaders) 1.192 +{ 1.193 + uint32_t i, count = mHeaders.Length(); 1.194 + for (i = 0; i < count; ++i) { 1.195 + const nsEntry &entry = mHeaders[i]; 1.196 + // prune proxy headers if requested 1.197 + if (pruneProxyHeaders && ((entry.header == nsHttp::Proxy_Authorization) || 1.198 + (entry.header == nsHttp::Proxy_Connection))) 1.199 + continue; 1.200 + buf.Append(entry.header); 1.201 + buf.AppendLiteral(": "); 1.202 + buf.Append(entry.value); 1.203 + buf.AppendLiteral("\r\n"); 1.204 + } 1.205 +} 1.206 + 1.207 +const char * 1.208 +nsHttpHeaderArray::PeekHeaderAt(uint32_t index, nsHttpAtom &header) const 1.209 +{ 1.210 + const nsEntry &entry = mHeaders[index]; 1.211 + 1.212 + header = entry.header; 1.213 + return entry.value.get(); 1.214 +} 1.215 + 1.216 +void 1.217 +nsHttpHeaderArray::Clear() 1.218 +{ 1.219 + mHeaders.Clear(); 1.220 +} 1.221 + 1.222 +} // namespace mozilla::net 1.223 +} // namespace mozilla