Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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) {
MOZ_COUNT_CTOR(nsHttpRequestHead);
nsHttpRequestHead& other = const_cast<nsHttpRequestHead&>(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) {
MOZ_COUNT_CTOR(nsHttpRequestHead);
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<nsHttpRequestHead&>(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<nsHttpRequestHead&>(*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<nsresult> 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