Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 ci et: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
10 #include "nsHttpHeaderArray.h"
11 #include "nsURLHelper.h"
12 #include "nsIHttpHeaderVisitor.h"
14 namespace mozilla {
15 namespace net {
17 //-----------------------------------------------------------------------------
18 // nsHttpHeaderArray <public>
19 //-----------------------------------------------------------------------------
20 nsresult
21 nsHttpHeaderArray::SetHeader(nsHttpAtom header,
22 const nsACString &value,
23 bool merge)
24 {
25 nsEntry *entry = nullptr;
26 int32_t index;
28 index = LookupEntry(header, &entry);
30 // If an empty value is passed in, then delete the header entry...
31 // unless we are merging, in which case this function becomes a NOP.
32 if (value.IsEmpty()) {
33 if (!merge && entry)
34 mHeaders.RemoveElementAt(index);
35 return NS_OK;
36 }
38 if (!entry) {
39 entry = mHeaders.AppendElement(); // new nsEntry()
40 if (!entry)
41 return NS_ERROR_OUT_OF_MEMORY;
42 entry->header = header;
43 entry->value = value;
44 } else if (merge && !IsSingletonHeader(header)) {
45 MergeHeader(header, entry, value);
46 } else {
47 // Replace the existing string with the new value
48 entry->value = value;
49 }
51 return NS_OK;
52 }
54 nsresult
55 nsHttpHeaderArray::SetHeaderFromNet(nsHttpAtom header, const nsACString &value)
56 {
57 nsEntry *entry = nullptr;
59 LookupEntry(header, &entry);
61 if (!entry) {
62 if (value.IsEmpty()) {
63 if (!TrackEmptyHeader(header)) {
64 LOG(("Ignoring Empty Header: %s\n", header.get()));
65 return NS_OK; // ignore empty headers by default
66 }
67 }
68 entry = mHeaders.AppendElement(); //new nsEntry(header, value);
69 if (!entry)
70 return NS_ERROR_OUT_OF_MEMORY;
71 entry->header = header;
72 entry->value = value;
73 } else if (!IsSingletonHeader(header)) {
74 MergeHeader(header, entry, value);
75 } else {
76 // Multiple instances of non-mergeable header received from network
77 // - ignore if same value
78 if (!entry->value.Equals(value)) {
79 if (IsSuspectDuplicateHeader(header)) {
80 // reply may be corrupt/hacked (ex: CLRF injection attacks)
81 return NS_ERROR_CORRUPTED_CONTENT;
82 } // else silently drop value: keep value from 1st header seen
83 LOG(("Header %s silently dropped as non mergeable header\n",
84 header.get()));
85 }
86 }
88 return NS_OK;
89 }
91 void
92 nsHttpHeaderArray::ClearHeader(nsHttpAtom header)
93 {
94 mHeaders.RemoveElement(header, nsEntry::MatchHeader());
95 }
97 const char *
98 nsHttpHeaderArray::PeekHeader(nsHttpAtom header) const
99 {
100 const nsEntry *entry = nullptr;
101 LookupEntry(header, &entry);
102 return entry ? entry->value.get() : nullptr;
103 }
105 nsresult
106 nsHttpHeaderArray::GetHeader(nsHttpAtom header, nsACString &result) const
107 {
108 const nsEntry *entry = nullptr;
109 LookupEntry(header, &entry);
110 if (!entry)
111 return NS_ERROR_NOT_AVAILABLE;
112 result = entry->value;
113 return NS_OK;
114 }
116 nsresult
117 nsHttpHeaderArray::VisitHeaders(nsIHttpHeaderVisitor *visitor)
118 {
119 NS_ENSURE_ARG_POINTER(visitor);
120 uint32_t i, count = mHeaders.Length();
121 for (i = 0; i < count; ++i) {
122 const nsEntry &entry = mHeaders[i];
123 if (NS_FAILED(visitor->VisitHeader(nsDependentCString(entry.header),
124 entry.value)))
125 break;
126 }
127 return NS_OK;
128 }
130 nsresult
131 nsHttpHeaderArray::ParseHeaderLine(const char *line,
132 nsHttpAtom *hdr,
133 char **val)
134 {
135 //
136 // BNF from section 4.2 of RFC 2616:
137 //
138 // message-header = field-name ":" [ field-value ]
139 // field-name = token
140 // field-value = *( field-content | LWS )
141 // field-content = <the OCTETs making up the field-value
142 // and consisting of either *TEXT or combinations
143 // of token, separators, and quoted-string>
144 //
146 // We skip over mal-formed headers in the hope that we'll still be able to
147 // do something useful with the response.
149 char *p = (char *) strchr(line, ':');
150 if (!p) {
151 LOG(("malformed header [%s]: no colon\n", line));
152 return NS_OK;
153 }
155 // make sure we have a valid token for the field-name
156 if (!nsHttp::IsValidToken(line, p)) {
157 LOG(("malformed header [%s]: field-name not a token\n", line));
158 return NS_OK;
159 }
161 *p = 0; // null terminate field-name
163 nsHttpAtom atom = nsHttp::ResolveAtom(line);
164 if (!atom) {
165 LOG(("failed to resolve atom [%s]\n", line));
166 return NS_OK;
167 }
169 // skip over whitespace
170 p = net_FindCharNotInSet(++p, HTTP_LWS);
172 // trim trailing whitespace - bug 86608
173 char *p2 = net_RFindCharNotInSet(p, HTTP_LWS);
175 *++p2 = 0; // null terminate header value; if all chars starting at |p|
176 // consisted of LWS, then p2 would have pointed at |p-1|, so
177 // the prefix increment is always valid.
179 // assign return values
180 if (hdr) *hdr = atom;
181 if (val) *val = p;
183 // assign response header
184 return SetHeaderFromNet(atom, nsDependentCString(p, p2 - p));
185 }
187 void
188 nsHttpHeaderArray::Flatten(nsACString &buf, bool pruneProxyHeaders)
189 {
190 uint32_t i, count = mHeaders.Length();
191 for (i = 0; i < count; ++i) {
192 const nsEntry &entry = mHeaders[i];
193 // prune proxy headers if requested
194 if (pruneProxyHeaders && ((entry.header == nsHttp::Proxy_Authorization) ||
195 (entry.header == nsHttp::Proxy_Connection)))
196 continue;
197 buf.Append(entry.header);
198 buf.AppendLiteral(": ");
199 buf.Append(entry.value);
200 buf.AppendLiteral("\r\n");
201 }
202 }
204 const char *
205 nsHttpHeaderArray::PeekHeaderAt(uint32_t index, nsHttpAtom &header) const
206 {
207 const nsEntry &entry = mHeaders[index];
209 header = entry.header;
210 return entry.value.get();
211 }
213 void
214 nsHttpHeaderArray::Clear()
215 {
216 mHeaders.Clear();
217 }
219 } // namespace mozilla::net
220 } // namespace mozilla