Petr Onderka has submitted this change and it was merged.
Change subject: added support for IPv6 anonymous users
......................................................................
added support for IPv6 anonymous users
Change-Id: I2af5ef6d84b7cf98d3fcfcbe8391dcbd976f51b5
---
M CMakeLists.txt
A DumpObjects/DumpIpV6User.cpp
A DumpObjects/DumpIpV6User.h
M DumpObjects/DumpNamedUser.cpp
M DumpObjects/DumpNamedUser.h
M DumpObjects/DumpTraits.h
M DumpObjects/DumpUser.cpp
M Incremental dumps.vcxproj
M Objects/IpV4User.cpp
M Objects/IpV4User.h
A Objects/IpV6User.cpp
A Objects/IpV6User.h
A Objects/NamedUser.cpp
A Objects/NamedUser.h
M Objects/Revision.h
M Objects/User.cpp
M Objects/User.h
M StringHelpers.cpp
M StringHelpers.h
M XmlContributorProcessor.cpp
20 files changed, 336 insertions(+), 61 deletions(-)
Approvals:
Petr Onderka: Verified; Looks good to me, approved
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d3de7a4..c1f8af5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,7 @@
Dump.cpp
DumpException.cpp
DumpObjects/DumpIpV4User.cpp
+ DumpObjects/DumpIpV6User.cpp
DumpObjects/DumpNamedUser.cpp
DumpObjects/DumpObject.cpp
DumpObjects/FileHeader.cpp
@@ -16,6 +17,8 @@
DumpObjects/DumpRevision.cpp
DumpObjects/DumpUser.cpp
Objects/IpV4User.cpp
+ Objects/IpV6User.cpp
+ Objects/NamedUser.cpp
main.cpp
DumpObjects/Offset.cpp
Objects/Page.cpp
@@ -43,6 +46,7 @@
set(SOURCES_files_ClInclude
DumpException.h
DumpObjects/DumpIpV4User.h
+ DumpObjects/DumpIpV6User.h
DumpObjects/DumpNamedUser.h
DumpObjects/DumpObjectKind.h
DumpObjects/DumpPage.h
@@ -61,6 +65,8 @@
Indexes/IndexNode.h
DumpObjects/Offset.h
Objects/IpV4User.h
+ Objects/IpV6User.h
+ Objects/NamedUser.h
Objects/Page.h
Objects/Revision.h
Indexes/Iterators/IndexIterator.h
diff --git a/DumpObjects/DumpIpV6User.cpp b/DumpObjects/DumpIpV6User.cpp
new file mode 100644
index 0000000..fd8a280
--- /dev/null
+++ b/DumpObjects/DumpIpV6User.cpp
@@ -0,0 +1,27 @@
+#include "DumpIpV6User.h"
+
+void DumpIpV6User::WriteInternal()
+{
+ WriteValue(user->Address);
+}
+
+unique_ptr<DumpUser> DumpIpV6User::Read(istream &stream)
+{
+ auto address = DumpTraits<std::array<std::uint16_t, 8>>::Read(stream);
+
+ return unique_ptr<DumpUser>(new
DumpIpV6User(std::make_shared<IpV6User>(address)));
+}
+
+DumpIpV6User::DumpIpV6User(shared_ptr<IpV6User> user)
+ : user(user)
+{}
+
+shared_ptr<User> DumpIpV6User::GetUser() const
+{
+ return user;
+}
+
+uint32_t DumpIpV6User::NewLength()
+{
+ return ValueSize(user->Address);
+}
\ No newline at end of file
diff --git a/DumpObjects/DumpIpV6User.h b/DumpObjects/DumpIpV6User.h
new file mode 100644
index 0000000..c99c6a8
--- /dev/null
+++ b/DumpObjects/DumpIpV6User.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "DumpUser.h"
+#include "../Objects/IpV6User.h"
+
+class DumpIpV6User : public DumpUser
+{
+protected:
+ virtual void WriteInternal();
+public:
+ static unique_ptr<DumpUser> Read(istream &stream);
+
+ shared_ptr<IpV6User> user;
+
+ DumpIpV6User(shared_ptr<IpV6User> user);
+
+ virtual shared_ptr<User> GetUser() const override;
+ virtual uint32_t NewLength() override;
+};
\ No newline at end of file
diff --git a/DumpObjects/DumpNamedUser.cpp b/DumpObjects/DumpNamedUser.cpp
index 70eb884..29bb8d5 100644
--- a/DumpObjects/DumpNamedUser.cpp
+++ b/DumpObjects/DumpNamedUser.cpp
@@ -1,4 +1,5 @@
#include "DumpNamedUser.h"
+#include "../Objects/NamedUser.h"
void DumpNamedUser::WriteInternal()
{
@@ -8,13 +9,13 @@
unique_ptr<DumpUser> DumpNamedUser::Read(istream &stream)
{
- int userId = DumpTraits<uint32_t>::Read(stream);
+ uint32_t userId = DumpTraits<uint32_t>::Read(stream);
string userName = DumpTraits<string>::Read(stream);
- return unique_ptr<DumpUser>(new DumpNamedUser(shared_ptr<User>(new
User(userId, userName))));
+ return unique_ptr<DumpUser>(new
DumpNamedUser(std::make_shared<NamedUser>(userId, userName)));
}
-DumpNamedUser::DumpNamedUser(shared_ptr<User> user)
+DumpNamedUser::DumpNamedUser(shared_ptr<NamedUser> user)
: user(user)
{}
diff --git a/DumpObjects/DumpNamedUser.h b/DumpObjects/DumpNamedUser.h
index e547ae0..c349d24 100644
--- a/DumpObjects/DumpNamedUser.h
+++ b/DumpObjects/DumpNamedUser.h
@@ -1,6 +1,7 @@
#pragma once
#include "DumpUser.h"
+#include "../Objects/NamedUser.h"
class DumpNamedUser : public DumpUser
{
@@ -9,9 +10,9 @@
public:
static unique_ptr<DumpUser> Read(istream &stream);
- shared_ptr<User> user;
+ shared_ptr<NamedUser> user;
- DumpNamedUser(shared_ptr<User> user);
+ DumpNamedUser(shared_ptr<NamedUser> user);
virtual shared_ptr<User> GetUser() const override;
virtual uint32_t NewLength() override;
diff --git a/DumpObjects/DumpTraits.h b/DumpObjects/DumpTraits.h
index a4c74a7..2bfae8f 100644
--- a/DumpObjects/DumpTraits.h
+++ b/DumpObjects/DumpTraits.h
@@ -5,6 +5,7 @@
#include <memory>
#include <string>
#include <iostream>
+#include <array>
#include <vector>
#include "../DumpException.h"
@@ -231,7 +232,7 @@
return result;
}
- static void Write(ostream &stream, const vector<T> value)
+ static void Write(ostream &stream, const vector<T> &value)
{
auto length = value.size();
@@ -246,7 +247,7 @@
}
}
- static uint32_t DumpSize(const vector<T> value)
+ static uint32_t DumpSize(const vector<T> &value)
{
uint32_t size = DumpTraits<uint16_t>::DumpSize(value.size());
@@ -257,4 +258,41 @@
return size;
}
+};
+
+template<typename T, size_t N>
+class DumpTraits<std::array<T, N>>
+{
+public:
+ static std::array<T, N> Read(istream &stream)
+ {
+ std::array<T, N> result;
+
+ for (int i = 0; i < N; i++)
+ {
+ result[i] = DumpTraits<T>::Read(stream);
+ }
+
+ return result;
+ }
+
+ static void Write(ostream &stream, const std::array<T, N> &value)
+ {
+ for (T item : value)
+ {
+ DumpTraits<T>::Write(stream, item);
+ }
+ }
+
+ static uint32_t DumpSize(const std::array<T, N> &value)
+ {
+ uint32_t size = 0;
+
+ for (T item : value)
+ {
+ size += DumpTraits<T>::DumpSize(item);
+ }
+
+ return size;
+ }
};
\ No newline at end of file
diff --git a/DumpObjects/DumpUser.cpp b/DumpObjects/DumpUser.cpp
index 847cc66..64aa042 100644
--- a/DumpObjects/DumpUser.cpp
+++ b/DumpObjects/DumpUser.cpp
@@ -1,19 +1,24 @@
-#include "DumpUser.h"
#include "DumpIpV4User.h"
+#include "DumpIpV6User.h"
#include "DumpNamedUser.h"
using std::dynamic_pointer_cast;
unique_ptr<DumpUser> DumpUser::Create(shared_ptr<User> user)
{
- DumpUser *result;
auto ipV4User = dynamic_pointer_cast<IpV4User>(user);
if (ipV4User != nullptr)
- result = new DumpIpV4User(ipV4User);
- else
- result = new DumpNamedUser(user);
+ return unique_ptr<DumpUser>(new DumpIpV4User(ipV4User));
+
+ auto ipV6User = dynamic_pointer_cast<IpV6User>(user);
+ if (ipV6User != nullptr)
+ return unique_ptr<DumpUser>(new DumpIpV6User(ipV6User));
- return unique_ptr<DumpUser>(result);
+ auto namedUser = dynamic_pointer_cast<NamedUser>(user);
+ if (namedUser != nullptr)
+ return unique_ptr<DumpUser>(new DumpNamedUser(namedUser));
+
+ throw DumpException();
}
unique_ptr<DumpUser> DumpUser::Read(RevisionFlags flags, istream &stream)
diff --git a/Incremental dumps.vcxproj b/Incremental dumps.vcxproj
index efcf938..7bd5c80 100644
--- a/Incremental dumps.vcxproj
+++ b/Incremental dumps.vcxproj
@@ -83,11 +83,13 @@
<ClCompile Include="Dump.cpp" />
<ClCompile Include="DumpException.cpp" />
<ClCompile Include="DumpObjects\DumpIpV4User.cpp" />
+ <ClCompile Include="DumpObjects\DumpIpV6User.cpp" />
<ClCompile Include="DumpObjects\DumpNamedUser.cpp" />
<ClCompile Include="DumpObjects\DumpObject.cpp" />
<ClCompile Include="DumpObjects\FileHeader.cpp" />
<ClInclude Include="DumpException.h" />
<ClInclude Include="DumpObjects\DumpIpV4User.h" />
+ <ClInclude Include="DumpObjects\DumpIpV6User.h" />
<ClInclude Include="DumpObjects\DumpNamedUser.h" />
<ClInclude Include="DumpObjects\DumpObjectKind.h" />
<ClInclude Include="DumpObjects\DumpPage.h" />
@@ -112,6 +114,8 @@
<ClCompile Include="Objects\IpV4User.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="DumpObjects\Offset.cpp" />
+ <ClCompile Include="Objects\IpV6User.cpp" />
+ <ClCompile Include="Objects\NamedUser.cpp" />
<ClCompile Include="Objects\Page.cpp" />
<ClCompile Include="Objects\Revision.cpp" />
<ClCompile Include="SevenZip.cpp" />
@@ -141,6 +145,8 @@
<ClInclude Include="Indexes\IndexNode.h" />
<ClInclude Include="DumpObjects\Offset.h" />
<ClInclude Include="Objects\IpV4User.h" />
+ <ClInclude Include="Objects\IpV6User.h" />
+ <ClInclude Include="Objects\NamedUser.h" />
<ClInclude Include="Objects\Page.h" />
<ClInclude Include="Objects\Revision.h" />
<ClInclude Include="Indexes\Iterators\IndexIterator.h" />
@@ -175,4 +181,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/Objects/IpV4User.cpp b/Objects/IpV4User.cpp
index b6af351..e32395f 100644
--- a/Objects/IpV4User.cpp
+++ b/Objects/IpV4User.cpp
@@ -7,9 +7,11 @@
using std::stoi;
using std::ostringstream;
-uint32_t IpV4User::ParseAddress(string address)
+uint32_t IpV4User::TryParseAddress(string address, bool &success)
{
- vector<string> stringParts = split(address, '.');
+ success = false;
+
+ std::vector<std::string> stringParts = split(address, '.');
if (stringParts.size() != 4)
return 0;
@@ -17,12 +19,25 @@
for (int i = 0; i < 4; i++)
{
- int intPart = stoi(stringParts[i]);
- if (intPart > 255 || intPart < 0)
+ bool success;
+ long intPart = tryParseLong(stringParts[i], success);
+ if (!success || intPart > 255 || intPart < 0)
return 0;
result |= (uint32_t)(uint8_t)intPart << (8 * i);
}
+
+ success = true;
+ return result;
+}
+
+uint32_t IpV4User::ParseAddress(string address)
+{
+ bool success;
+ uint32_t result = TryParseAddress(address, success);
+
+ if (!success)
+ throw DumpException();
return result;
}
@@ -45,17 +60,11 @@
IpV4User::IpV4User(string stringAddress)
: User(0, stringAddress), Address(ParseAddress(stringAddress))
-{
- if (Address == 0)
- throw new DumpException();
-}
+{}
IpV4User::IpV4User(string stringAddress, uint32_t parsedAddress)
: User(0, stringAddress), Address(parsedAddress)
-{
- if (Address == 0)
- throw new DumpException();
-}
+{}
IpV4User::IpV4User(uint32_t parsedAddress)
: User(0, AddressToString(parsedAddress)), Address(parsedAddress)
diff --git a/Objects/IpV4User.h b/Objects/IpV4User.h
index b7a234d..e9af543 100644
--- a/Objects/IpV4User.h
+++ b/Objects/IpV4User.h
@@ -5,6 +5,7 @@
class IpV4User : public User
{
public:
+ static uint32_t TryParseAddress(string address, bool &success);
static uint32_t ParseAddress(string address);
static string AddressToString(uint32_t address);
diff --git a/Objects/IpV6User.cpp b/Objects/IpV6User.cpp
new file mode 100644
index 0000000..3d8c7bf
--- /dev/null
+++ b/Objects/IpV6User.cpp
@@ -0,0 +1,78 @@
+#include "IpV6User.h"
+#include <sstream>
+#include "../StringHelpers.h"
+#include "../DumpException.h"
+#include "Revision.h"
+
+using std::stoi;
+using std::ostringstream;
+
+std::array<uint16_t, 8> IpV6User::TryParseAddress(string address, bool
&success)
+{
+ success = false;
+
+ std::vector<std::string> stringParts = split(address, ':');
+ if (stringParts.size() != 8)
+ return std::array<uint16_t, 8>();
+
+ std::array<uint16_t, 8> result;
+
+ for (int i = 0; i < 8; i++)
+ {
+ bool success;
+ long intPart = tryParseLong(stringParts[i], success, 16);
+ if (!success || intPart > 0xFFFF || intPart < 0)
+ return std::array<uint16_t, 8>();
+
+ result[i] = intPart;
+ }
+
+ success = true;
+ return result;
+}
+
+std::array<uint16_t, 8> IpV6User::ParseAddress(string address)
+{
+ bool success;
+ auto result = TryParseAddress(address, success);
+
+ if (!success)
+ throw DumpException();
+
+ return result;
+}
+
+string IpV6User::AddressToString(std::array<uint16_t, 8> address)
+{
+ ostringstream s;
+
+ s << std::hex << std::uppercase;
+
+ for (int i = 0; i < 8; i++)
+ {
+ if (i != 0)
+ s << ':';
+
+ s << address[i];
+ }
+
+ return s.str();
+}
+
+IpV6User::IpV6User(string stringAddress)
+ : User(0, stringAddress), Address(ParseAddress(stringAddress))
+{
+}
+
+IpV6User::IpV6User(string stringAddress, std::array<uint16_t, 8> parsedAddress)
+ : User(0, stringAddress), Address(parsedAddress)
+{}
+
+IpV6User::IpV6User(std::array<uint16_t, 8> parsedAddress)
+ : User(0, AddressToString(parsedAddress)), Address(parsedAddress)
+{}
+
+RevisionFlags IpV6User::UserKind() const
+{
+ return RevisionFlags::IpV6User;
+}
\ No newline at end of file
diff --git a/Objects/IpV6User.h b/Objects/IpV6User.h
new file mode 100644
index 0000000..38d2442
--- /dev/null
+++ b/Objects/IpV6User.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <array>
+#include "User.h"
+
+class IpV6User : public User
+{
+public:
+ static std::array<uint16_t, 8> TryParseAddress(string address, bool
&success);
+ static std::array<uint16_t, 8> ParseAddress(string address);
+ static string AddressToString(std::array<uint16_t, 8> address);
+
+ IpV6User(string stringAddress);
+ IpV6User(string stringAddress, std::array<uint16_t, 8> parsedAddress);
+ IpV6User(std::array<uint16_t, 8> parsedAddress);
+
+ std::array<uint16_t, 8> Address;
+
+ virtual RevisionFlags UserKind() const override;
+};
\ No newline at end of file
diff --git a/Objects/NamedUser.cpp b/Objects/NamedUser.cpp
new file mode 100644
index 0000000..1e73426
--- /dev/null
+++ b/Objects/NamedUser.cpp
@@ -0,0 +1,11 @@
+#include "NamedUser.h"
+#include "Revision.h"
+
+NamedUser::NamedUser(std::uint32_t userId, string userName)
+ : User(userId, userName)
+{}
+
+RevisionFlags NamedUser::UserKind() const
+{
+ return RevisionFlags::NamedUser;
+}
\ No newline at end of file
diff --git a/Objects/NamedUser.h b/Objects/NamedUser.h
new file mode 100644
index 0000000..4127117
--- /dev/null
+++ b/Objects/NamedUser.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "User.h"
+
+class NamedUser : public User
+{
+public:
+ NamedUser(std::uint32_t userId, string userName);
+
+ virtual RevisionFlags UserKind() const override;
+};
\ No newline at end of file
diff --git a/Objects/Revision.h b/Objects/Revision.h
index 940a0ac..cf80de7 100644
--- a/Objects/Revision.h
+++ b/Objects/Revision.h
@@ -15,7 +15,8 @@
Minor = 0x01,
NamedUser = 0x10,
- IpV4User = 0x20
+ IpV4User = 0x20,
+ IpV6User = 0x40
};
RevisionFlags operator |(RevisionFlags first, RevisionFlags second);
diff --git a/Objects/User.cpp b/Objects/User.cpp
index 83ef349..b7b6ce1 100644
--- a/Objects/User.cpp
+++ b/Objects/User.cpp
@@ -1,27 +1,50 @@
#include "User.h"
#include "IpV4User.h"
-#include "Revision.h"
+#include "IpV6User.h"
+#include "NamedUser.h"
+#include "../DumpException.h"
+
+unique_ptr<User> TryCreateFromIp(string ipAddress, bool &success)
+{
+ uint32_t ipV4 = IpV4User::TryParseAddress(ipAddress, success);
+ if (success)
+ return unique_ptr<User>(new IpV4User(ipAddress, ipV4));
+
+ auto ipV6 = IpV6User::TryParseAddress(ipAddress, success);
+ if (success)
+ return unique_ptr<User>(new IpV6User(ipAddress, ipV6));
+
+ success = false;
+ return nullptr;
+}
unique_ptr<User> User::Create(uint32_t userId, string userName)
{
- User *result;
- uint32_t ipV4 = IpV4User::ParseAddress(userName);
- if (ipV4 != 0)
- result = new IpV4User(userName, ipV4);
- else
- result = new User(userId, userName);
+ if (userId == 0)
+ {
+ bool success;
- return unique_ptr<User>(result);
+ auto ipUser = TryCreateFromIp(userName, success);
+
+ if (success)
+ return ipUser;
+ }
+
+ return unique_ptr<User>(new NamedUser(userId, userName));
+}
+
+unique_ptr<User> User::CreateFromIp(string ipAddress)
+{
+ bool success;
+
+ auto ipUser = TryCreateFromIp(ipAddress, success);
+
+ if (!success)
+ throw DumpException();
+
+ return ipUser;
}
User::User(uint32_t userId, string userName)
: UserId(userId), UserName(userName)
-{}
-
-RevisionFlags User::UserKind() const
-{
- return RevisionFlags::NamedUser;
-}
-
-User::~User()
{}
\ No newline at end of file
diff --git a/Objects/User.h b/Objects/User.h
index b91ce91..9729c23 100644
--- a/Objects/User.h
+++ b/Objects/User.h
@@ -10,17 +10,18 @@
enum class RevisionFlags : uint8_t;
-// TODO: create class NamedUser?
class User
{
+protected:
+ User(uint32_t userId, string userName);
public:
static unique_ptr<User> Create(uint32_t userId, string userName);
-
- User(uint32_t userId, string userName);
+ // creates IPv4 or IPv6 anonymous users
+ static unique_ptr<User> CreateFromIp(string ipAddress);
uint32_t UserId;
string UserName;
- virtual RevisionFlags UserKind() const;
- virtual ~User();
+ virtual RevisionFlags UserKind() const = 0;
+ virtual ~User() {}
};
\ No newline at end of file
diff --git a/StringHelpers.cpp b/StringHelpers.cpp
index ddcedf4..d960735 100644
--- a/StringHelpers.cpp
+++ b/StringHelpers.cpp
@@ -1,17 +1,33 @@
#include "StringHelpers.h"
#include <sstream>
-using std::stringstream;
-
// http://stackoverflow.com/a/236803/41071
-vector<string> split(const string &s, char delim)
+std::vector<std::string> split(const std::string &s, char delim)
{
- vector<string> elems;
- stringstream ss(s);
- string item;
+ std::vector<std::string> elems;
+ std::stringstream ss(s);
+ std::string item;
while (getline(ss, item, delim))
{
elems.push_back(item);
}
return elems;
+}
+
+long tryParseLong(const std::string &s, bool &success, int radix)
+{
+ char* end;
+ const char* start = s.c_str();
+ long result = strtol(start, &end, radix);
+
+ if (errno == 0 && end != start && *end=='\0')
+ {
+ success = true;
+ return result;
+ }
+ else
+ {
+ success = false;
+ return 0;
+ }
}
\ No newline at end of file
diff --git a/StringHelpers.h b/StringHelpers.h
index 472ad87..83b7bb5 100644
--- a/StringHelpers.h
+++ b/StringHelpers.h
@@ -3,7 +3,7 @@
#include <string>
#include <vector>
-using std::string;
-using std::vector;
+std::vector<std::string> split(const std::string &s, char delim);
-vector<string> split(const string &s, char delim);
\ No newline at end of file
+// makes sure the whole string is converted to an int
+long tryParseLong(const std::string &s, bool &success, int radix = 10);
\ No newline at end of file
diff --git a/XmlContributorProcessor.cpp b/XmlContributorProcessor.cpp
index 8651b23..f67f71c 100644
--- a/XmlContributorProcessor.cpp
+++ b/XmlContributorProcessor.cpp
@@ -1,7 +1,8 @@
#include "XmlContributorProcessor.h"
#include "XmlUtils.h"
#include "Objects/Revision.h"
-#include "Objects/IpV4User.h"
+#include "Objects/User.h"
+#include "Objects/NamedUser.h"
void XmlContributorProcessor::Handler(XML::Element &elem, void *userData)
{
@@ -20,12 +21,12 @@
auto revision = (Revision*)userData;
- User* user;
+ std::shared_ptr<User> user;
if (processor.ip != string())
- user = new IpV4User(processor.ip);
+ user = User::CreateFromIp(processor.ip);
else
- user = new User(processor.id, processor.userName);
+ user = std::make_shared<NamedUser>(processor.id, processor.userName);
revision->Contributor = shared_ptr<User>(user);
revision->Flags |= user->UserKind();
--
To view, visit https://gerrit.wikimedia.org/r/75864
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I2af5ef6d84b7cf98d3fcfcbe8391dcbd976f51b5
Gerrit-PatchSet: 2
Gerrit-Project: operations/dumps/incremental
Gerrit-Branch: gsoc
Gerrit-Owner: Petr Onderka <[email protected]>
Gerrit-Reviewer: Petr Onderka <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits