/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // HttpLog.h should generally be included first #include "HttpLog.h" #include "nsHttpRequestHead.h" #include "nsIHttpHeaderVisitor.h" //----------------------------------------------------------------------------- // nsHttpRequestHead //----------------------------------------------------------------------------- namespace mozilla { namespace net { nsHttpRequestHead::nsHttpRequestHead() { MOZ_COUNT_CTOR(nsHttpRequestHead); } nsHttpRequestHead::nsHttpRequestHead(const nsHttpRequestHead& aRequestHead) { nsHttpRequestHead& other = const_cast(aRequestHead); RecursiveMutexAutoLock monitor(other.mRecursiveMutex); mHeaders = other.mHeaders; mMethod = other.mMethod; mVersion = other.mVersion; mRequestURI = other.mRequestURI; mPath = other.mPath; mOrigin = other.mOrigin; mParsedMethod = other.mParsedMethod; mHTTPS = other.mHTTPS; mInVisitHeaders = false; } nsHttpRequestHead::nsHttpRequestHead(nsHttpRequestHead&& aRequestHead) { nsHttpRequestHead& other = aRequestHead; RecursiveMutexAutoLock monitor(other.mRecursiveMutex); mHeaders = std::move(other.mHeaders); mMethod = std::move(other.mMethod); mVersion = std::move(other.mVersion); mRequestURI = std::move(other.mRequestURI); mPath = std::move(other.mPath); mOrigin = std::move(other.mOrigin); mParsedMethod = std::move(other.mParsedMethod); mHTTPS = std::move(other.mHTTPS); mInVisitHeaders = false; } nsHttpRequestHead::~nsHttpRequestHead() { MOZ_COUNT_DTOR(nsHttpRequestHead); } nsHttpRequestHead& nsHttpRequestHead::operator=( const nsHttpRequestHead& aRequestHead) { nsHttpRequestHead& other = const_cast(aRequestHead); RecursiveMutexAutoLock monitorOther(other.mRecursiveMutex); RecursiveMutexAutoLock monitor(mRecursiveMutex); mHeaders = other.mHeaders; mMethod = other.mMethod; mVersion = other.mVersion; mRequestURI = other.mRequestURI; mPath = other.mPath; mOrigin = other.mOrigin; mParsedMethod = other.mParsedMethod; mHTTPS = other.mHTTPS; mInVisitHeaders = false; return *this; } // Don't use this function. It is only used by HttpChannelParent to avoid // copying of request headers!!! const nsHttpHeaderArray& nsHttpRequestHead::Headers() const { nsHttpRequestHead& curr = const_cast(*this); curr.mRecursiveMutex.AssertCurrentThreadIn(); return mHeaders; } void nsHttpRequestHead::SetHeaders(const nsHttpHeaderArray& aHeaders) { RecursiveMutexAutoLock mon(mRecursiveMutex); mHeaders = aHeaders; } void nsHttpRequestHead::SetVersion(HttpVersion version) { RecursiveMutexAutoLock mon(mRecursiveMutex); mVersion = version; } void nsHttpRequestHead::SetRequestURI(const nsACString& s) { RecursiveMutexAutoLock mon(mRecursiveMutex); mRequestURI = s; } void nsHttpRequestHead::SetPath(const nsACString& s) { RecursiveMutexAutoLock mon(mRecursiveMutex); mPath = s; } uint32_t nsHttpRequestHead::HeaderCount() { RecursiveMutexAutoLock mon(mRecursiveMutex); return mHeaders.Count(); } nsresult nsHttpRequestHead::VisitHeaders( nsIHttpHeaderVisitor* visitor, nsHttpHeaderArray::VisitorFilter filter /* = nsHttpHeaderArray::eFilterAll*/) { RecursiveMutexAutoLock mon(mRecursiveMutex); mInVisitHeaders = true; nsresult rv = mHeaders.VisitHeaders(visitor, filter); mInVisitHeaders = false; return rv; } void nsHttpRequestHead::Method(nsACString& aMethod) { RecursiveMutexAutoLock mon(mRecursiveMutex); aMethod = mMethod; } HttpVersion nsHttpRequestHead::Version() { RecursiveMutexAutoLock mon(mRecursiveMutex); return mVersion; } void nsHttpRequestHead::RequestURI(nsACString& aRequestURI) { RecursiveMutexAutoLock mon(mRecursiveMutex); aRequestURI = mRequestURI; } void nsHttpRequestHead::Path(nsACString& aPath) { RecursiveMutexAutoLock mon(mRecursiveMutex); aPath = mPath.IsEmpty() ? mRequestURI : mPath; } void nsHttpRequestHead::SetHTTPS(bool val) { RecursiveMutexAutoLock mon(mRecursiveMutex); mHTTPS = val; } void nsHttpRequestHead::Origin(nsACString& aOrigin) { RecursiveMutexAutoLock mon(mRecursiveMutex); aOrigin = mOrigin; } nsresult nsHttpRequestHead::SetHeader(const nsACString& h, const nsACString& v, bool m /*= false*/) { RecursiveMutexAutoLock mon(mRecursiveMutex); if (mInVisitHeaders) { return NS_ERROR_FAILURE; } return mHeaders.SetHeader(h, v, m, nsHttpHeaderArray::eVarietyRequestOverride); } nsresult nsHttpRequestHead::SetHeader(const nsHttpAtom& h, const nsACString& v, bool m /*= false*/) { RecursiveMutexAutoLock mon(mRecursiveMutex); if (mInVisitHeaders) { return NS_ERROR_FAILURE; } return mHeaders.SetHeader(h, v, m, nsHttpHeaderArray::eVarietyRequestOverride); } nsresult nsHttpRequestHead::SetHeader( const nsHttpAtom& h, const nsACString& v, bool m, nsHttpHeaderArray::HeaderVariety variety) { RecursiveMutexAutoLock mon(mRecursiveMutex); if (mInVisitHeaders) { return NS_ERROR_FAILURE; } return mHeaders.SetHeader(h, v, m, variety); } nsresult nsHttpRequestHead::SetEmptyHeader(const nsACString& h) { RecursiveMutexAutoLock mon(mRecursiveMutex); if (mInVisitHeaders) { return NS_ERROR_FAILURE; } return mHeaders.SetEmptyHeader(h, nsHttpHeaderArray::eVarietyRequestOverride); } nsresult nsHttpRequestHead::GetHeader(const nsHttpAtom& h, nsACString& v) { v.Truncate(); RecursiveMutexAutoLock mon(mRecursiveMutex); return mHeaders.GetHeader(h, v); } nsresult nsHttpRequestHead::ClearHeader(const nsHttpAtom& h) { RecursiveMutexAutoLock mon(mRecursiveMutex); if (mInVisitHeaders) { return NS_ERROR_FAILURE; } mHeaders.ClearHeader(h); return NS_OK; } void nsHttpRequestHead::ClearHeaders() { RecursiveMutexAutoLock mon(mRecursiveMutex); if (mInVisitHeaders) { return; } mHeaders.Clear(); } bool nsHttpRequestHead::HasHeader(const nsHttpAtom& h) { RecursiveMutexAutoLock mon(mRecursiveMutex); return mHeaders.HasHeader(h); } bool nsHttpRequestHead::HasHeaderValue(const nsHttpAtom& h, const char* v) { RecursiveMutexAutoLock mon(mRecursiveMutex); return mHeaders.HasHeaderValue(h, v); } nsresult nsHttpRequestHead::SetHeaderOnce(const nsHttpAtom& h, const char* v, bool merge /*= false */) { RecursiveMutexAutoLock mon(mRecursiveMutex); if (mInVisitHeaders) { return NS_ERROR_FAILURE; } if (!merge || !mHeaders.HasHeaderValue(h, v)) { return mHeaders.SetHeader(h, nsDependentCString(v), merge, nsHttpHeaderArray::eVarietyRequestOverride); } return NS_OK; } nsHttpRequestHead::ParsedMethodType nsHttpRequestHead::ParsedMethod() { RecursiveMutexAutoLock mon(mRecursiveMutex); return mParsedMethod; } bool nsHttpRequestHead::EqualsMethod(ParsedMethodType aType) { RecursiveMutexAutoLock mon(mRecursiveMutex); return mParsedMethod == aType; } void nsHttpRequestHead::ParseHeaderSet(const char* buffer) { RecursiveMutexAutoLock mon(mRecursiveMutex); nsHttpAtom hdr; nsAutoCString headerNameOriginal; nsAutoCString val; while (buffer) { const char* eof = strchr(buffer, '\r'); if (!eof) { break; } if (NS_SUCCEEDED(nsHttpHeaderArray::ParseHeaderLine( nsDependentCSubstring(buffer, eof - buffer), &hdr, &headerNameOriginal, &val))) { DebugOnly rv = mHeaders.SetHeaderFromNet(hdr, headerNameOriginal, val, false); MOZ_ASSERT(NS_SUCCEEDED(rv)); } buffer = eof + 1; if (*buffer == '\n') { buffer++; } } } bool nsHttpRequestHead::IsHTTPS() { RecursiveMutexAutoLock mon(mRecursiveMutex); return mHTTPS; } void nsHttpRequestHead::SetMethod(const nsACString& method) { RecursiveMutexAutoLock mon(mRecursiveMutex); mMethod = method; ParseMethod(mMethod, mParsedMethod); } // static void nsHttpRequestHead::ParseMethod(const nsCString& aRawMethod, ParsedMethodType& aParsedMethod) { aParsedMethod = kMethod_Custom; if (!strcmp(aRawMethod.get(), "GET")) { aParsedMethod = kMethod_Get; } else if (!strcmp(aRawMethod.get(), "POST")) { aParsedMethod = kMethod_Post; } else if (!strcmp(aRawMethod.get(), "OPTIONS")) { aParsedMethod = kMethod_Options; } else if (!strcmp(aRawMethod.get(), "CONNECT")) { aParsedMethod = kMethod_Connect; } else if (!strcmp(aRawMethod.get(), "HEAD")) { aParsedMethod = kMethod_Head; } else if (!strcmp(aRawMethod.get(), "PUT")) { aParsedMethod = kMethod_Put; } else if (!strcmp(aRawMethod.get(), "TRACE")) { aParsedMethod = kMethod_Trace; } } void nsHttpRequestHead::SetOrigin(const nsACString& scheme, const nsACString& host, int32_t port) { RecursiveMutexAutoLock mon(mRecursiveMutex); mOrigin.Assign(scheme); mOrigin.AppendLiteral("://"); mOrigin.Append(host); if (port >= 0) { mOrigin.AppendLiteral(":"); mOrigin.AppendInt(port); } } bool nsHttpRequestHead::IsSafeMethod() { RecursiveMutexAutoLock mon(mRecursiveMutex); // This code will need to be extended for new safe methods, otherwise // they'll default to "not safe". if ((mParsedMethod == kMethod_Get) || (mParsedMethod == kMethod_Head) || (mParsedMethod == kMethod_Options) || (mParsedMethod == kMethod_Trace)) { return true; } if (mParsedMethod != kMethod_Custom) { return false; } return (!strcmp(mMethod.get(), "PROPFIND") || !strcmp(mMethod.get(), "REPORT") || !strcmp(mMethod.get(), "SEARCH")); } void nsHttpRequestHead::Flatten(nsACString& buf, bool pruneProxyHeaders) { RecursiveMutexAutoLock mon(mRecursiveMutex); // note: the first append is intentional. buf.Append(mMethod); buf.Append(' '); buf.Append(mRequestURI); buf.AppendLiteral(" HTTP/"); switch (mVersion) { case HttpVersion::v1_1: buf.AppendLiteral("1.1"); break; case HttpVersion::v0_9: buf.AppendLiteral("0.9"); break; default: buf.AppendLiteral("1.0"); } buf.AppendLiteral("\r\n"); mHeaders.Flatten(buf, pruneProxyHeaders, false); } } // namespace net } // namespace mozilla