Bug 1267130 - Improve the URL segment calculation, r=valentin

This commit is contained in:
Andrea Marchesini 2016-05-10 10:52:19 +02:00
Родитель 77024304e3
Коммит 61b52e4aa3
2 изменённых файлов: 113 добавлений и 35 удалений

Просмотреть файл

@ -469,19 +469,28 @@ nsStandardURL::CoalescePath(netCoalesceFlags coalesceFlag, char *path)
}
uint32_t
nsStandardURL::AppendSegmentToBuf(char *buf, uint32_t i, const char *str, URLSegment &seg, const nsCString *escapedStr, bool useEscaped)
nsStandardURL::AppendSegmentToBuf(char *buf, uint32_t i, const char *str,
const URLSegment &segInput, URLSegment &segOutput,
const nsCString *escapedStr,
bool useEscaped, int32_t *diff)
{
if (seg.mLen > 0) {
MOZ_ASSERT(segInput.mLen == segOutput.mLen);
if (diff) *diff = 0;
if (segInput.mLen > 0) {
if (useEscaped) {
seg.mLen = escapedStr->Length();
memcpy(buf + i, escapedStr->get(), seg.mLen);
MOZ_ASSERT(diff);
segOutput.mLen = escapedStr->Length();
*diff = segOutput.mLen - segInput.mLen;
memcpy(buf + i, escapedStr->get(), segOutput.mLen);
} else {
memcpy(buf + i, str + segInput.mPos, segInput.mLen);
}
else
memcpy(buf + i, str + seg.mPos, seg.mLen);
seg.mPos = i;
i += seg.mLen;
segOutput.mPos = i;
i += segOutput.mLen;
} else {
seg.mPos = i;
segOutput.mPos = i;
}
return i;
}
@ -595,6 +604,20 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
}
}
// We must take a copy of every single segment because they are pointing to
// the |spec| while we are changing their value, in case we must use
// encoded strings.
URLSegment username(mUsername);
URLSegment password(mPassword);
URLSegment host(mHost);
URLSegment path(mPath);
URLSegment filepath(mFilepath);
URLSegment directory(mDirectory);
URLSegment basename(mBasename);
URLSegment extension(mExtension);
URLSegment query(mQuery);
URLSegment ref(mRef);
//
// generate the normalized URL string
//
@ -604,9 +627,10 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
char *buf;
mSpec.BeginWriting(buf);
uint32_t i = 0;
int32_t diff = 0;
if (mScheme.mLen > 0) {
i = AppendSegmentToBuf(buf, i, spec, mScheme);
i = AppendSegmentToBuf(buf, i, spec, mScheme, mScheme);
net_ToLowerCase(buf + mScheme.mPos, mScheme.mLen);
i = AppendToBuf(buf, i, "://", 3);
}
@ -616,15 +640,22 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
// append authority
if (mUsername.mLen > 0) {
i = AppendSegmentToBuf(buf, i, spec, mUsername, &encUsername, useEncUsername);
if (mPassword.mLen >= 0) {
i = AppendSegmentToBuf(buf, i, spec, username, mUsername,
&encUsername, useEncUsername, &diff);
ShiftFromPassword(diff);
if (password.mLen >= 0) {
buf[i++] = ':';
i = AppendSegmentToBuf(buf, i, spec, mPassword, &encPassword, useEncPassword);
i = AppendSegmentToBuf(buf, i, spec, password, mPassword,
&encPassword, useEncPassword, &diff);
ShiftFromHost(diff);
}
buf[i++] = '@';
}
if (mHost.mLen > 0) {
i = AppendSegmentToBuf(buf, i, spec, mHost, &encHost, useEncHost);
if (host.mLen > 0) {
i = AppendSegmentToBuf(buf, i, spec, host, mHost, &encHost, useEncHost,
&diff);
ShiftFromPath(diff);
net_ToLowerCase(buf + mHost.mPos, mHost.mLen);
MOZ_ASSERT(mPort >= -1, "Invalid negative mPort");
if (mPort != -1 && mPort != mDefaultPort) {
@ -649,21 +680,23 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
}
else {
uint32_t leadingSlash = 0;
if (spec[mPath.mPos] != '/') {
if (spec[path.mPos] != '/') {
LOG(("adding leading slash to path\n"));
leadingSlash = 1;
buf[i++] = '/';
// basename must exist, even if empty (bugs 113508, 429347)
if (mBasename.mLen == -1) {
mBasename.mPos = i;
mBasename.mLen = 0;
mBasename.mPos = basename.mPos = i;
mBasename.mLen = basename.mLen = 0;
}
}
// record corrected (file)path starting position
mPath.mPos = mFilepath.mPos = i - leadingSlash;
i = AppendSegmentToBuf(buf, i, spec, mDirectory, &encDirectory, useEncDirectory);
i = AppendSegmentToBuf(buf, i, spec, directory, mDirectory,
&encDirectory, useEncDirectory, &diff);
ShiftFromBasename(diff);
// the directory must end with a '/'
if (buf[i-1] != '/') {
@ -671,7 +704,9 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
mDirectory.mLen++;
}
i = AppendSegmentToBuf(buf, i, spec, mBasename, &encBasename, useEncBasename);
i = AppendSegmentToBuf(buf, i, spec, basename, mBasename,
&encBasename, useEncBasename, &diff);
ShiftFromExtension(diff);
// make corrections to directory segment if leadingSlash
if (leadingSlash) {
@ -684,18 +719,24 @@ nsStandardURL::BuildNormalizedSpec(const char *spec)
if (mExtension.mLen >= 0) {
buf[i++] = '.';
i = AppendSegmentToBuf(buf, i, spec, mExtension, &encExtension, useEncExtension);
i = AppendSegmentToBuf(buf, i, spec, extension, mExtension,
&encExtension, useEncExtension, &diff);
ShiftFromQuery(diff);
}
// calculate corrected filepath length
mFilepath.mLen = i - mFilepath.mPos;
if (mQuery.mLen >= 0) {
buf[i++] = '?';
i = AppendSegmentToBuf(buf, i, spec, mQuery, &encQuery, useEncQuery);
i = AppendSegmentToBuf(buf, i, spec, query, mQuery,
&encQuery, useEncQuery,
&diff);
ShiftFromRef(diff);
}
if (mRef.mLen >= 0) {
buf[i++] = '#';
i = AppendSegmentToBuf(buf, i, spec, mRef, &encRef, useEncRef);
i = AppendSegmentToBuf(buf, i, spec, ref, mRef, &encRef, useEncRef,
&diff);
}
// calculate corrected path length
mPath.mLen = i - mPath.mPos;
@ -958,6 +999,39 @@ nsStandardURL::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
#undef GOT_PREF
}
#define SHIFT_FROM(name, what) \
void \
nsStandardURL::name(int32_t diff) \
{ \
if (!diff) return; \
if (what.mLen >= 0) { \
CheckedInt<int32_t> pos = what.mPos; \
pos += diff; \
MOZ_ASSERT(pos.isValid()); \
what.mPos = pos.value(); \
}
#define SHIFT_FROM_NEXT(name, what, next) \
SHIFT_FROM(name, what) \
next(diff); \
}
#define SHIFT_FROM_LAST(name, what) \
SHIFT_FROM(name, what) \
}
SHIFT_FROM_NEXT(ShiftFromAuthority, mAuthority, ShiftFromUsername)
SHIFT_FROM_NEXT(ShiftFromUsername, mUsername, ShiftFromPassword)
SHIFT_FROM_NEXT(ShiftFromPassword, mPassword, ShiftFromHost)
SHIFT_FROM_NEXT(ShiftFromHost, mHost, ShiftFromPath)
SHIFT_FROM_NEXT(ShiftFromPath, mPath, ShiftFromFilepath)
SHIFT_FROM_NEXT(ShiftFromFilepath, mFilepath, ShiftFromDirectory)
SHIFT_FROM_NEXT(ShiftFromDirectory, mDirectory, ShiftFromBasename)
SHIFT_FROM_NEXT(ShiftFromBasename, mBasename, ShiftFromExtension)
SHIFT_FROM_NEXT(ShiftFromExtension, mExtension, ShiftFromQuery)
SHIFT_FROM_NEXT(ShiftFromQuery, mQuery, ShiftFromRef)
SHIFT_FROM_LAST(ShiftFromRef, mRef)
//----------------------------------------------------------------------------
// nsStandardURL::nsISupports
//----------------------------------------------------------------------------

Просмотреть файл

@ -80,6 +80,7 @@ public: /* internal -- HPUX compiler can't handle this being private */
URLSegment() : mPos(0), mLen(-1) {}
URLSegment(uint32_t pos, int32_t len) : mPos(pos), mLen(len) {}
URLSegment(const URLSegment& aCopy) : mPos(aCopy.mPos), mLen(aCopy.mLen) {}
void Reset() { mPos = 0; mLen = -1; }
// Merge another segment following this one to it if they're contiguous
// Assumes we have something like "foo;bar" where this object is 'foo' and right
@ -181,7 +182,10 @@ private:
nsresult NormalizeIDN(const nsCSubstring &host, nsCString &result);
void CoalescePath(netCoalesceFlags coalesceFlag, char *path);
uint32_t AppendSegmentToBuf(char *, uint32_t, const char *, URLSegment &, const nsCString *esc=nullptr, bool useEsc = false);
uint32_t AppendSegmentToBuf(char *, uint32_t, const char *,
const URLSegment &input, URLSegment &output,
const nsCString *esc=nullptr,
bool useEsc = false, int32_t* diff = nullptr);
uint32_t AppendToBuf(char *, uint32_t, const char *, uint32_t);
nsresult BuildNormalizedSpec(const char *spec);
@ -220,17 +224,17 @@ private:
const nsDependentCSubstring Ref() { return Segment(mRef); }
// shift the URLSegments to the right by diff
void ShiftFromAuthority(int32_t diff) { mAuthority.mPos += diff; ShiftFromUsername(diff); }
void ShiftFromUsername(int32_t diff) { mUsername.mPos += diff; ShiftFromPassword(diff); }
void ShiftFromPassword(int32_t diff) { mPassword.mPos += diff; ShiftFromHost(diff); }
void ShiftFromHost(int32_t diff) { mHost.mPos += diff; ShiftFromPath(diff); }
void ShiftFromPath(int32_t diff) { mPath.mPos += diff; ShiftFromFilepath(diff); }
void ShiftFromFilepath(int32_t diff) { mFilepath.mPos += diff; ShiftFromDirectory(diff); }
void ShiftFromDirectory(int32_t diff) { mDirectory.mPos += diff; ShiftFromBasename(diff); }
void ShiftFromBasename(int32_t diff) { mBasename.mPos += diff; ShiftFromExtension(diff); }
void ShiftFromExtension(int32_t diff) { mExtension.mPos += diff; ShiftFromQuery(diff); }
void ShiftFromQuery(int32_t diff) { mQuery.mPos += diff; ShiftFromRef(diff); }
void ShiftFromRef(int32_t diff) { mRef.mPos += diff; }
void ShiftFromAuthority(int32_t diff);
void ShiftFromUsername(int32_t diff);
void ShiftFromPassword(int32_t diff);
void ShiftFromHost(int32_t diff);
void ShiftFromPath(int32_t diff);
void ShiftFromFilepath(int32_t diff);
void ShiftFromDirectory(int32_t diff);
void ShiftFromBasename(int32_t diff);
void ShiftFromExtension(int32_t diff);
void ShiftFromQuery(int32_t diff);
void ShiftFromRef(int32_t diff);
// fastload helper functions
nsresult ReadSegment(nsIBinaryInputStream *, URLSegment &);