/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla. * * The Initial Developer of the Original Code is Netscape * Communications. Portions created by Netscape Communications are * Copyright (C) 2001 by Netscape Communications. All * Rights Reserved. * * Contributor(s): * Darin Fisher (original author) */ #include "nsHttpHeaderArray.h" #include "nsHttp.h" //----------------------------------------------------------------------------- // nsHttpHeaderArray //----------------------------------------------------------------------------- nsresult nsHttpHeaderArray::SetHeader(nsHttpAtom header, const nsACString &value, PRBool merge) { nsEntry *entry = nsnull; PRInt32 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) { mHeaders.RemoveElementAt(index); delete entry; } return NS_OK; } // Create a new entry, or... if (!entry) { entry = new nsEntry(header, value); if (!entry) return NS_ERROR_OUT_OF_MEMORY; if (!mHeaders.AppendElement(entry)) { NS_WARNING("AppendElement failed"); delete entry; } } // Append the new value to the existing value iff... else if (merge && CanAppendToHeader(header)) { if (header == nsHttp::Set_Cookie || header == nsHttp::WWW_Authenticate || header == nsHttp::Proxy_Authenticate) // Special case these headers and use a newline delimiter to // delimit the values from one another as commas may appear // in the values of these headers contrary to what the spec says. entry->value.Append('\n'); else // Delimit each value from the others using a comma (per HTTP spec) entry->value.Append(", "); entry->value.Append(value); } // Replace the existing string with the new value else entry->value = value; return NS_OK; } void nsHttpHeaderArray::ClearHeader(nsHttpAtom header) { nsEntry *entry = nsnull; PRInt32 index; index = LookupEntry(header, &entry); if (entry) { mHeaders.RemoveElementAt(index); delete entry; } } const char * nsHttpHeaderArray::PeekHeader(nsHttpAtom header) { nsEntry *entry = nsnull; LookupEntry(header, &entry); return entry ? entry->value.get() : nsnull; } nsresult nsHttpHeaderArray::GetHeader(nsHttpAtom header, nsACString &result) { nsEntry *entry = nsnull; LookupEntry(header, &entry); if (!entry) return NS_ERROR_NOT_AVAILABLE; result = entry->value; return NS_OK; } nsresult nsHttpHeaderArray::VisitHeaders(nsIHttpHeaderVisitor *visitor) { NS_ENSURE_ARG_POINTER(visitor); PRInt32 i, count = mHeaders.Count(); for (i=0; iVisitHeader(nsDependentCString(entry->header), entry->value))) break; } return NS_OK; } void nsHttpHeaderArray::ParseHeaderLine(char *line, nsHttpAtom *hdr, char **val) { // // Augmented BNF (from section 4.2 of RFC 2616 w/ modifications): // // message-header = field-name field-sep [ field-value ] // field-name = token // field-sep = LWS ( ":" | "=" | SP | HT ) // field-value = *( field-content | LWS ) // field-content = // // Here, we allow a greater set of possible header value separators // for compatibility with the vast number of broken web servers (mostly // lame CGI scripts). NN4 and IE are similarly tolerant. // // // Examples: // // Header: Value // Header :Value // Header Value // Header=Value // char *p = (char *) strchr(line, ':'); if (!p) p = net_FindCharInSet(line, " \t="); if (p) { // ignore whitespace between header name and colon char *p2 = net_FindCharInSet(line, p, HTTP_LWS); *p2 = 0; // null terminate header name nsHttpAtom atom = nsHttp::ResolveAtom(line); if (atom) { // skip over whitespace p = net_FindCharNotInSet(++p, HTTP_LWS); // trim trailing whitespace - bug 86608 p2 = net_RFindCharNotInSet(p, HTTP_LWS); *++p2 = 0; // null terminate header value; if all chars // starting at |p| consisted of LWS, then p2 // would have pointed at |p-1|, so the prefix // increment is always valid. // assign return values if (hdr) *hdr = atom; if (val) *val = p; // assign response header SetHeader(atom, nsDependentCString(p, p2 - p), PR_TRUE); } else LOG(("unknown header; skipping\n")); } else LOG(("malformed header\n")); // We ignore mal-formed headers in the hope that we'll still be able // to do something useful with the response. } void nsHttpHeaderArray::Flatten(nsACString &buf, PRBool pruneProxyHeaders) { PRInt32 i, count = mHeaders.Count(); for (i=0; iheader == nsHttp::Proxy_Authorization) || (entry->header == nsHttp::Proxy_Connection))) continue; buf.Append(entry->header); buf.Append(": "); buf.Append(entry->value); buf.Append("\r\n"); } } const char * nsHttpHeaderArray::PeekHeaderAt(PRUint32 index, nsHttpAtom &header) { nsEntry *entry = (nsEntry *) mHeaders[index]; if (!entry) return nsnull; header = entry->header; return entry->value.get(); } void nsHttpHeaderArray::Clear() { PRInt32 i, count = mHeaders.Count(); for (i=0; i //----------------------------------------------------------------------------- PRInt32 nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry) { PRInt32 i, count = mHeaders.Count(); for (i=0; iheader == header) return i; } *entry = nsnull; return -1; } PRBool nsHttpHeaderArray::CanAppendToHeader(nsHttpAtom header) { return header != nsHttp::Content_Type && header != nsHttp::Content_Length && header != nsHttp::User_Agent && header != nsHttp::Referer && header != nsHttp::Host && header != nsHttp::Authorization && header != nsHttp::Proxy_Authorization && header != nsHttp::If_Modified_Since && header != nsHttp::If_Unmodified_Since && header != nsHttp::From && header != nsHttp::Location && header != nsHttp::Max_Forwards; }